aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken2/ApiExtractor
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken2/ApiExtractor')
-rw-r--r--sources/shiboken2/ApiExtractor/AUTHORS8
-rw-r--r--sources/shiboken2/ApiExtractor/CMakeLists.txt90
-rw-r--r--sources/shiboken2/ApiExtractor/COPYING342
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp3459
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder.h106
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h194
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.cpp2784
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang.h1976
-rw-r--r--sources/shiboken2/ApiExtractor/abstractmetalang_typedefs.h50
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractor.cpp317
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractor.h111
-rw-r--r--sources/shiboken2/ApiExtractor/apiextractormacros.h41
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp770
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h58
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp150
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h48
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp266
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangparser.h93
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp227
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/clangutils.h101
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp155
-rw-r--r--sources/shiboken2/ApiExtractor/clangparser/compilersupport.h40
-rw-r--r--sources/shiboken2/ApiExtractor/cmake_uninstall.cmake21
-rw-r--r--sources/shiboken2/ApiExtractor/dependency.h43
-rw-r--r--sources/shiboken2/ApiExtractor/doc/CMakeLists.txt10
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_templates/index.html27
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_templates/layout.html41
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/searchbox.html12
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.pngbin0 -> 36012 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpgbin0 -> 14237 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.pngbin0 -> 101 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpgbin0 -> 3138 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.pngbin0 -> 4702 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpgbin0 -> 2660 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.pngbin0 -> 4618 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidedocs.css409
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.pngbin0 -> 12969 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.pngbin0 -> 130 bytes
-rw-r--r--sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/theme.conf7
-rw-r--r--sources/shiboken2/ApiExtractor/doc/conf.py.in163
-rw-r--r--sources/shiboken2/ApiExtractor/doc/contents.rst9
-rw-r--r--sources/shiboken2/ApiExtractor/doc/dependency-apiextractor.svg360
-rw-r--r--sources/shiboken2/ApiExtractor/doc/overview.rst15
-rw-r--r--sources/shiboken2/ApiExtractor/doc/ownership.rst85
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem.rst29
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_arguments.rst192
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_conversionrule.rst113
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_documentation.rst43
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst132
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_modify_function.rst78
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_solving_compilation.rst70
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst371
-rw-r--r--sources/shiboken2/ApiExtractor/doc/typesystem_templates.rst55
-rw-r--r--sources/shiboken2/ApiExtractor/docparser.cpp174
-rw-r--r--sources/shiboken2/ApiExtractor/docparser.h127
-rw-r--r--sources/shiboken2/ApiExtractor/doxygenparser.cpp198
-rw-r--r--sources/shiboken2/ApiExtractor/doxygenparser.h43
-rw-r--r--sources/shiboken2/ApiExtractor/fileout.cpp231
-rw-r--r--sources/shiboken2/ApiExtractor/fileout.h62
-rw-r--r--sources/shiboken2/ApiExtractor/graph.cpp135
-rw-r--r--sources/shiboken2/ApiExtractor/graph.h72
-rw-r--r--sources/shiboken2/ApiExtractor/header_paths.h62
-rw-r--r--sources/shiboken2/ApiExtractor/icecc.cmake11
-rw-r--r--sources/shiboken2/ApiExtractor/include.cpp71
-rw-r--r--sources/shiboken2/ApiExtractor/include.h92
-rw-r--r--sources/shiboken2/ApiExtractor/merge.xsl82
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.cpp1207
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel.h687
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel_enums.h38
-rw-r--r--sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h82
-rw-r--r--sources/shiboken2/ApiExtractor/qtdocparser.cpp189
-rw-r--r--sources/shiboken2/ApiExtractor/qtdocparser.h44
-rw-r--r--sources/shiboken2/ApiExtractor/reporthandler.cpp149
-rw-r--r--sources/shiboken2/ApiExtractor/reporthandler.h71
-rw-r--r--sources/shiboken2/ApiExtractor/symbols.filter7
-rw-r--r--sources/shiboken2/ApiExtractor/tests/CMakeLists.txt74
-rw-r--r--sources/shiboken2/ApiExtractor/tests/a.xml13
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp527
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.h55
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp216
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h47
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp453
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testaddfunction.h54
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp130
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testarrayargument.h42
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp106
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcodeinjection.h45
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcontainer.cpp105
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testcontainer.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testconversionoperator.cpp188
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testconversionoperator.h44
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testconversionruletag.cpp250
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testconversionruletag.h43
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testctorinformation.cpp76
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testctorinformation.h44
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp145
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testdroptypeentries.h44
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp86
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testdtorinformation.h46
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testenum.cpp416
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testenum.h47
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testextrainclude.cpp85
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testextrainclude.h42
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testfunctiontag.cpp97
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testfunctiontag.h42
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testimplicitconversions.cpp163
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testimplicitconversions.h46
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testinserttemplate.cpp130
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testinserttemplate.h44
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp80
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp249
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h45
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp75
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.h43
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testnamespace.cpp96
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testnamespace.h44
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testnestedtypes.cpp128
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testnestedtypes.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.cpp119
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.h42
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.cpp60
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp100
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testrefcounttag.h42
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testreferencetopointer.cpp59
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testreferencetopointer.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testremovefield.cpp62
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testremovefield.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testremoveimplconv.cpp69
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testremoveimplconv.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp117
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp64
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testresolvetype.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp139
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testreverseoperators.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.cpp439
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtemplates.h51
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtoposort.cpp69
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtoposort.h42
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp71
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testtyperevision.h42
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testutil.h78
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.cpp64
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.h41
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testvoidarg.cpp87
-rw-r--r--sources/shiboken2/ApiExtractor/tests/testvoidarg.h42
-rw-r--r--sources/shiboken2/ApiExtractor/tests/utf8code.txt1
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.cpp745
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase.h186
-rw-r--r--sources/shiboken2/ApiExtractor/typedatabase_typedefs.h49
-rw-r--r--sources/shiboken2/ApiExtractor/typeparser.cpp318
-rw-r--r--sources/shiboken2/ApiExtractor/typeparser.h60
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.cpp2737
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem.h1975
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_enums.h86
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_p.h176
-rw-r--r--sources/shiboken2/ApiExtractor/typesystem_typedefs.h49
159 files changed, 30901 insertions, 0 deletions
diff --git a/sources/shiboken2/ApiExtractor/AUTHORS b/sources/shiboken2/ApiExtractor/AUTHORS
new file mode 100644
index 000000000..6e802fb53
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/AUTHORS
@@ -0,0 +1,8 @@
+Anderson Lizardo <anderson.lizardo@openbossa.org>
+Bruno Araujo <bruno.araujo@openbossa.org>
+Hugo Parente Lima <hugo.lima@openbossa.org>
+Lauro Moura <lauro.neto@openbossa.org>
+Luciano Wolf <luciano.wolf@openbossa.org>
+Marcelo Lira <marcelo.lira@openbossa.org>
+Renato Araujo Oliveira Filho <renato.filho@openbossa.org>
+
diff --git a/sources/shiboken2/ApiExtractor/CMakeLists.txt b/sources/shiboken2/ApiExtractor/CMakeLists.txt
new file mode 100644
index 000000000..6cb3e0185
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt
@@ -0,0 +1,90 @@
+project(apiextractor)
+
+find_package(LibXml2 2.6.32)
+find_package(LibXslt 1.1.19)
+
+option(DISABLE_DOCSTRINGS "Disable documentation extraction." FALSE)
+
+if (NOT DISABLE_DOCSTRINGS)
+ if (NOT LIBXSLT_FOUND OR NOT LIBXML2_FOUND)
+ set(DISABLE_DOCSTRINGS TRUE CACHE BOOL "Disable doc strings" PARENT_SCOPE)
+ set(DISABLE_DOCSTRINGS TRUE)
+ message(WARNING "libxslt and/or libxml not found, disabling support for doc strings!")
+ endif()
+endif()
+
+if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release)
+endif()
+
+if(BUILD_TESTS)
+ set(LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/tests)
+endif ()
+
+set(QT_USE_QTCORE 1)
+set(QT_USE_QTXML 1)
+add_definitions(-DQT_PLUGIN)
+add_definitions(-DQT_SHARED)
+add_definitions(-DRXX_ALLOCATOR_INIT_0)
+
+set(apiextractor_SRC
+apiextractor.cpp
+abstractmetabuilder.cpp
+abstractmetalang.cpp
+fileout.cpp
+graph.cpp
+reporthandler.cpp
+typeparser.cpp
+typesystem.cpp
+include.cpp
+typedatabase.cpp
+# Clang
+clangparser/compilersupport.cpp
+clangparser/clangparser.cpp
+clangparser/clangbuilder.cpp
+clangparser/clangdebugutils.cpp
+clangparser/clangutils.cpp
+# Old parser
+parser/codemodel.cpp
+)
+
+set(APIEXTRACTOR_EXTRA_INCLUDES ${CLANG_EXTRA_INCLUDES})
+set(APIEXTRACTOR_EXTRA_LIBRARIES ${CLANG_EXTRA_LIBRARIES})
+
+if (NOT DISABLE_DOCSTRINGS)
+ set(apiextractor_SRC
+ ${apiextractor_SRC}
+ docparser.cpp
+ doxygenparser.cpp
+ qtdocparser.cpp
+ )
+ set(APIEXTRACTOR_EXTRA_INCLUDES ${APIEXTRACTOR_EXTRA_INCLUDES} ${LIBXSLT_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR})
+ set(APIEXTRACTOR_EXTRA_LIBRARIES ${APIEXTRACTOR_EXTRA_LIBRARIES} ${LIBXSLT_LIBRARIES} ${LIBXML2_LIBRARIES})
+endif()
+
+set(LIB_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/lib${LIB_SUFFIX}" CACHE PATH "The subdirectory relative to the install prefix where libraries will be installed (default is /lib${LIB_SUFFIX})" FORCE)
+
+set(CMAKE_AUTOMOC ON)
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/parser
+ ${CMAKE_CURRENT_SOURCE_DIR}/parser/rpp
+ ${APIEXTRACTOR_EXTRA_INCLUDES}
+ ${Qt5Core_INCLUDE_DIRS}
+ ${Qt5Xml_INCLUDE_DIRS}
+ )
+
+add_library(apiextractor STATIC ${apiextractor_SRC} ${apiextractor_RCCS_SRC})
+target_link_libraries(apiextractor
+ ${Qt5Xml_LIBRARIES}
+ ${Qt5XmlPatterns_LIBRARIES}
+ ${APIEXTRACTOR_EXTRA_LIBRARIES}
+ )
+
+set_property(TARGET apiextractor PROPERTY CXX_STANDARD 11)
+
+if (BUILD_TESTS)
+ enable_testing()
+ add_subdirectory(tests)
+endif()
diff --git a/sources/shiboken2/ApiExtractor/COPYING b/sources/shiboken2/ApiExtractor/COPYING
new file mode 100644
index 000000000..4ccd71466
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/COPYING
@@ -0,0 +1,342 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
+-------------------------------------------------------------------------
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
new file mode 100644
index 000000000..3b2ecf8e1
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp
@@ -0,0 +1,3459 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "abstractmetabuilder_p.h"
+#include "reporthandler.h"
+#include "typedatabase.h"
+
+#include <clangparser/clangbuilder.h>
+#include <clangparser/clangutils.h>
+
+#include "parser/codemodel.h"
+
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QFileInfo>
+#include <QRegularExpression>
+#include <QTextCodec>
+#include <QTextStream>
+#include <QVariant>
+#include <QTime>
+#include <QQueue>
+#include <QDir>
+
+#include <cstdio>
+#include <algorithm>
+#include "graph.h"
+#include <QTemporaryFile>
+
+static inline QString colonColon() { return QStringLiteral("::"); }
+
+static QString stripTemplateArgs(const QString &name)
+{
+ int pos = name.indexOf(QLatin1Char('<'));
+ return pos < 0 ? name : name.left(pos);
+}
+
+static QStringList parseTemplateType(const QString& name) {
+ int n = name.indexOf(QLatin1Char('<'));
+ if (n <= 0) {
+ // If name starts with '<' or contains an unmatched (i.e. any) '>', we
+ // reject it
+ if (n == 0 || name.count(QLatin1Char('>')))
+ return QStringList();
+ // Doesn't look like a template instantiation; just return the name
+ return QStringList() << name;
+ }
+
+ // Split the type name into the template name and template arguments; the
+ // part before the opening '<' is the template name
+ //
+ // Example:
+ // "foo<A, bar<B, C>, D>" -> ( "foo", "A", "bar<B, C>", "D" )
+ QStringList result;
+ result << name.left(n).trimmed();
+
+ // Extract template arguments
+ int i, depth = 1;
+ const int l = name.length();
+ for (i = n + 1; i < l; ++i) {
+ // Consume balanced '<'/'>' within a single argument so that we won't
+ // split on ',' as part of a single argument which is itself a
+ // multi-argument template type
+ if (name[i] == QLatin1Char('<')) {
+ ++depth;
+ } else if (name[i] == QLatin1Char('>')) {
+ if (--depth == 0)
+ break;
+ } else if (name[i] == QLatin1Char(',') && depth == 1) {
+ // Encountered ',' in template argument list that is not within
+ // another template name; add current argument to result and start
+ // working on the next argument
+ result << name.mid(n + 1, i - n - 1).trimmed();
+ n = i;
+ }
+ }
+ if (i >= l) // arg list not closed
+ return QStringList();
+ if (i + 1 < l) // arg list closed before end of name
+ return QStringList();
+
+ // Add final argument and return result
+ result << name.mid(n + 1, i - n - 1).trimmed();
+ return result;
+}
+
+AbstractMetaBuilderPrivate::AbstractMetaBuilderPrivate() : m_currentClass(0),
+ m_logDirectory(QLatin1String(".") + QDir::separator())
+{
+}
+
+AbstractMetaBuilderPrivate::~AbstractMetaBuilderPrivate()
+{
+ qDeleteAll(m_globalEnums);
+ qDeleteAll(m_globalFunctions);
+ qDeleteAll(m_templates);
+ qDeleteAll(m_smartPointers);
+ qDeleteAll(m_metaClasses);
+}
+
+AbstractMetaBuilder::AbstractMetaBuilder() : d(new AbstractMetaBuilderPrivate)
+{
+ d->q = this;
+}
+
+AbstractMetaBuilder::~AbstractMetaBuilder()
+{
+ delete d;
+}
+
+AbstractMetaClassList AbstractMetaBuilder::classes() const
+{
+ return d->m_metaClasses;
+}
+
+AbstractMetaClassList AbstractMetaBuilder::templates() const
+{
+ return d->m_templates;
+}
+
+AbstractMetaClassList AbstractMetaBuilder::smartPointers() const
+{
+ return d->m_smartPointers;
+}
+
+AbstractMetaFunctionList AbstractMetaBuilder::globalFunctions() const
+{
+ return d->m_globalFunctions;
+}
+
+AbstractMetaEnumList AbstractMetaBuilder::globalEnums() const
+{
+ return d->m_globalEnums;
+}
+
+QSet<QString> AbstractMetaBuilder::qtMetaTypeDeclaredTypeNames() const
+{
+ return d->m_qmetatypeDeclaredTypenames;
+}
+
+void AbstractMetaBuilderPrivate::checkFunctionModifications()
+{
+ TypeDatabase *types = TypeDatabase::instance();
+ const SingleTypeEntryHash entryHash = types->entries();
+
+ for (SingleTypeEntryHash::const_iterator it = entryHash.cbegin(), end = entryHash.cend(); it != end; ++it) {
+ const TypeEntry *entry = it.value();
+ if (!entry)
+ continue;
+ if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing)
+ continue;
+
+ const ComplexTypeEntry* centry = static_cast<const ComplexTypeEntry*>(entry);
+ FunctionModificationList modifications = centry->functionModifications();
+
+ for (const FunctionModification &modification : qAsConst(modifications)) {
+ QString signature = modification.signature;
+
+ QString name = signature.trimmed();
+ name.truncate(name.indexOf(QLatin1Char('(')));
+
+ AbstractMetaClass *clazz = AbstractMetaClass::findClass(m_metaClasses, centry->qualifiedCppName());
+ if (!clazz)
+ continue;
+
+ const AbstractMetaFunctionList functions = clazz->functions();
+ bool found = false;
+ QStringList possibleSignatures;
+ for (AbstractMetaFunction *function : functions) {
+ if (function->minimalSignature() == signature && function->implementingClass() == clazz) {
+ found = true;
+ break;
+ }
+
+ if (function->originalName() == name) {
+ possibleSignatures.append(function->minimalSignature() + QLatin1String(" in ")
+ + function->implementingClass()->name());
+ }
+ }
+
+ if (!found) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("signature '%1' for function modification in '%2' not found. Possible candidates: %3")
+ .arg(signature, clazz->qualifiedCppName(), possibleSignatures.join(QLatin1String(", ")));
+ }
+ }
+ }
+}
+
+AbstractMetaClass *AbstractMetaBuilderPrivate::argumentToClass(ArgumentModelItem argument)
+{
+ AbstractMetaClass* returned = 0;
+ bool ok = false;
+ AbstractMetaType* type = translateType(argument->type(), &ok);
+ if (ok && type && type->typeEntry() && type->typeEntry()->isComplex()) {
+ const TypeEntry *entry = type->typeEntry();
+ returned = AbstractMetaClass::findClass(m_metaClasses, entry->name());
+ }
+ delete type;
+ return returned;
+}
+
+AbstractMetaClass *AbstractMetaBuilder::createMetaClass()
+{
+ return new AbstractMetaClass();
+}
+
+AbstractMetaEnum *AbstractMetaBuilder::createMetaEnum()
+{
+ return new AbstractMetaEnum();
+}
+
+AbstractMetaEnumValue *AbstractMetaBuilder::createMetaEnumValue()
+{
+ return new AbstractMetaEnumValue();
+}
+
+AbstractMetaField *AbstractMetaBuilder::createMetaField()
+{
+ return new AbstractMetaField();
+}
+
+AbstractMetaFunction *AbstractMetaBuilder::createMetaFunction()
+{
+ return new AbstractMetaFunction();
+}
+
+AbstractMetaArgument *AbstractMetaBuilder::createMetaArgument()
+{
+ return new AbstractMetaArgument();
+}
+
+AbstractMetaType *AbstractMetaBuilder::createMetaType()
+{
+ return new AbstractMetaType();
+}
+
+/**
+ * Checks the argument of a hash function and flags the type if it is a complex type
+ */
+void AbstractMetaBuilderPrivate::registerHashFunction(FunctionModelItem function_item)
+{
+ ArgumentList arguments = function_item->arguments();
+ if (arguments.size() == 1) {
+ if (AbstractMetaClass *cls = argumentToClass(arguments.at(0)))
+ cls->setHasHashFunction(true);
+ }
+}
+
+/**
+ * Check if a class has a debug stream operator that can be used as toString
+ */
+
+void AbstractMetaBuilderPrivate::registerToStringCapability(FunctionModelItem function_item)
+{
+ ArgumentList arguments = function_item->arguments();
+ if (arguments.size() == 2) {
+ if (arguments.at(0)->type().toString() == QLatin1String("QDebug")) {
+ ArgumentModelItem arg = arguments.at(1);
+ if (AbstractMetaClass *cls = argumentToClass(arg)) {
+ if (arg->type().indirections() < 2)
+ cls->setToStringCapability(true);
+ }
+ }
+ }
+}
+
+void AbstractMetaBuilderPrivate::traverseOperatorFunction(FunctionModelItem item)
+{
+ if (item->accessPolicy() != CodeModel::Public)
+ return;
+
+ ArgumentList arguments = item->arguments();
+ AbstractMetaClass* baseoperandClass;
+ bool firstArgumentIsSelf = true;
+ bool unaryOperator = false;
+
+ baseoperandClass = argumentToClass(arguments.at(0));
+
+ if (arguments.size() == 1) {
+ unaryOperator = true;
+ } else if (!baseoperandClass
+ || !(baseoperandClass->typeEntry()->codeGeneration() & TypeEntry::GenerateTargetLang)) {
+ baseoperandClass = argumentToClass(arguments.at(1));
+ firstArgumentIsSelf = false;
+ } else {
+ bool ok;
+ AbstractMetaType* type = translateType(item->type(), &ok);
+ const TypeEntry* retType = ok ? type->typeEntry() : 0;
+ AbstractMetaClass* otherArgClass = argumentToClass(arguments.at(1));
+ if (otherArgClass && retType
+ && (retType->isValue() || retType->isObject())
+ && retType != baseoperandClass->typeEntry()
+ && retType == otherArgClass->typeEntry()) {
+ baseoperandClass = AbstractMetaClass::findClass(m_metaClasses, retType);
+ firstArgumentIsSelf = false;
+ }
+ delete type;
+ }
+
+ if (baseoperandClass) {
+ AbstractMetaClass* oldCurrentClass = m_currentClass;
+ m_currentClass = baseoperandClass;
+ AbstractMetaFunction *metaFunction = traverseFunction(item);
+ if (metaFunction && !metaFunction->isInvalid()) {
+ // Strip away first argument, since that is the containing object
+ AbstractMetaArgumentList arguments = metaFunction->arguments();
+ if (firstArgumentIsSelf || unaryOperator) {
+ AbstractMetaArgument* first = arguments.takeFirst();
+ if (!unaryOperator && first->type()->indirections())
+ metaFunction->setPointerOperator(true);
+ delete first;
+ metaFunction->setArguments(arguments);
+ } else {
+ // If the operator method is not unary and the first operator is
+ // not of the same type of its owning class we suppose that it
+ // must be an reverse operator (e.g. CLASS::operator(TYPE, CLASS)).
+ // All operator overloads that operate over a class are already
+ // being added as member functions of that class by the API Extractor.
+ AbstractMetaArgument* last = arguments.takeLast();
+ if (last->type()->indirections())
+ metaFunction->setPointerOperator(true);
+ delete last;
+
+ metaFunction->setArguments(arguments);
+ metaFunction->setReverseOperator(true);
+ }
+ metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction);
+ metaFunction->setVisibility(AbstractMetaFunction::Public);
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ setupFunctionDefaults(metaFunction, baseoperandClass);
+ baseoperandClass->addFunction(metaFunction);
+ Q_ASSERT(!metaFunction->wasPrivate());
+ } else if (metaFunction) {
+ delete metaFunction;
+ }
+
+ m_currentClass = oldCurrentClass;
+ }
+}
+
+void AbstractMetaBuilderPrivate::traverseStreamOperator(FunctionModelItem item)
+{
+ ArgumentList arguments = item->arguments();
+ if (arguments.size() == 2 && item->accessPolicy() == CodeModel::Public) {
+ AbstractMetaClass* streamClass = argumentToClass(arguments.at(0));
+ AbstractMetaClass* streamedClass = argumentToClass(arguments.at(1));
+
+ if (streamClass && streamedClass && (streamClass->isStream())) {
+ AbstractMetaClass *oldCurrentClass = m_currentClass;
+ m_currentClass = streamedClass;
+ AbstractMetaFunction *streamFunction = traverseFunction(item);
+
+ if (streamFunction && !streamFunction->isInvalid()) {
+ QString name = item->name();
+ streamFunction->setFunctionType(AbstractMetaFunction::GlobalScopeFunction);
+ // Strip first argument, since that is the containing object
+ AbstractMetaArgumentList arguments = streamFunction->arguments();
+ if (!streamClass->typeEntry()->generateCode())
+ delete arguments.takeLast();
+ else
+ delete arguments.takeFirst();
+
+ streamFunction->setArguments(arguments);
+
+ *streamFunction += AbstractMetaAttributes::Final;
+ *streamFunction += AbstractMetaAttributes::Public;
+ streamFunction->setOriginalAttributes(streamFunction->attributes());
+
+// streamFunction->setType(0);
+
+ AbstractMetaClass *funcClass;
+
+ if (!streamClass->typeEntry()->generateCode()) {
+ AbstractMetaArgumentList reverseArgs = reverseList(streamFunction->arguments());
+ streamFunction->setArguments(reverseArgs);
+ streamFunction->setReverseOperator(true);
+ funcClass = streamedClass;
+ } else {
+ funcClass = streamClass;
+ }
+
+ setupFunctionDefaults(streamFunction, funcClass);
+ funcClass->addFunction(streamFunction);
+ if (funcClass == streamClass)
+ funcClass->typeEntry()->addExtraInclude(streamedClass->typeEntry()->include());
+ else
+ funcClass->typeEntry()->addExtraInclude(streamClass->typeEntry()->include());
+
+ m_currentClass = oldCurrentClass;
+ } else if (streamFunction) {
+ delete streamFunction;
+ }
+
+ }
+ }
+}
+
+void AbstractMetaBuilderPrivate::fixQObjectForScope(const FileModelItem &dom,
+ const TypeDatabase *types,
+ const NamespaceModelItem &scope)
+{
+ const ClassList &scopeClasses = scope->classes();
+ for (const ClassModelItem &item : scopeClasses) {
+ QString qualifiedName = item->qualifiedName().join(colonColon());
+ TypeEntry* entry = types->findType(qualifiedName);
+ if (entry) {
+ if (isQObject(dom, qualifiedName) && entry->isComplex())
+ ((ComplexTypeEntry*) entry)->setQObject(true);
+ }
+ }
+
+ const NamespaceList &namespaces = scope->namespaces();
+ for (const NamespaceModelItem &n : namespaces) {
+ if (scope != n)
+ fixQObjectForScope(dom, types, n);
+ }
+}
+
+void AbstractMetaBuilderPrivate::sortLists()
+{
+ for (AbstractMetaClass *cls : qAsConst(m_metaClasses))
+ cls->sortFunctions();
+}
+
+FileModelItem AbstractMetaBuilderPrivate::buildDom(const QByteArrayList &arguments,
+ unsigned clangFlags)
+{
+ clang::Builder builder;
+ FileModelItem result = clang::parse(arguments, clangFlags, builder)
+ ? builder.dom() : FileModelItem();
+ const clang::BaseVisitor::Diagnostics &diagnostics = builder.diagnostics();
+ if (const int diagnosticsCount = diagnostics.size()) {
+ QDebug d = qWarning();
+ d.nospace();
+ d.noquote();
+ d << "Clang: " << diagnosticsCount << " diagnostic messages:\n";
+ for (int i = 0; i < diagnosticsCount; ++i)
+ d << " " << diagnostics.at(i) << '\n';
+ }
+ return result;
+}
+
+void AbstractMetaBuilderPrivate::traverseDom(const FileModelItem &dom)
+{
+ const TypeDatabase *types = TypeDatabase::instance();
+
+ pushScope(dom);
+
+ // fix up QObject's in the type system..
+ fixQObjectForScope(dom, types, dom);
+
+ // Start the generation...
+ const ClassList &typeValues = dom->classes();
+ ReportHandler::setProgressReference(typeValues);
+ for (const ClassModelItem &item : typeValues) {
+ ReportHandler::progress(QLatin1String("Generating class model..."));
+ AbstractMetaClass *cls = traverseClass(dom, item);
+ if (!cls)
+ continue;
+
+ addAbstractMetaClass(cls);
+ }
+
+ // We need to know all global enums
+ const EnumList &enums = dom->enums();
+ ReportHandler::setProgressReference(enums);
+ for (const EnumModelItem &item : enums) {
+ ReportHandler::progress(QLatin1String("Generating enum model..."));
+ AbstractMetaEnum *metaEnum = traverseEnum(item, 0, QSet<QString>());
+ if (metaEnum) {
+ if (metaEnum->typeEntry()->generateCode())
+ m_globalEnums << metaEnum;
+ }
+ }
+
+ const QSet<NamespaceModelItem> &namespaceTypeValues = dom->uniqueNamespaces();
+ ReportHandler::setProgressReference(namespaceTypeValues);
+ for (NamespaceModelItem item : namespaceTypeValues) {
+ ReportHandler::progress(QLatin1String("Generating namespace model..."));
+ AbstractMetaClass *metaClass = traverseNamespace(dom, item);
+ if (metaClass)
+ m_metaClasses << metaClass;
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ const TypeDefList typeDefs = dom->typeDefs();
+ ReportHandler::setProgressReference(typeDefs);
+ for (const TypeDefModelItem &typeDef : typeDefs) {
+ ReportHandler::progress(QLatin1String("Resolving typedefs..."));
+ AbstractMetaClass* cls = traverseTypeDef(dom, typeDef);
+ addAbstractMetaClass(cls);
+ }
+
+ figureOutEnumValues();
+
+ for (const ClassModelItem &item : typeValues)
+ traverseClassMembers(item);
+
+ for (const NamespaceModelItem &item : namespaceTypeValues)
+ traverseNamespaceMembers(item);
+
+ // Global functions
+ const FunctionList &functions = dom->functions();
+ for (const FunctionModelItem &func : functions) {
+ if (func->accessPolicy() != CodeModel::Public || func->name().startsWith(QLatin1String("operator")))
+ continue;
+
+ FunctionTypeEntry* funcEntry = types->findFunctionType(func->name());
+ if (!funcEntry || !funcEntry->generateCode())
+ continue;
+
+ AbstractMetaFunction* metaFunc = traverseFunction(func);
+ if (!metaFunc)
+ continue;
+
+ if (!funcEntry->hasSignature(metaFunc->minimalSignature())) {
+ delete metaFunc;
+ continue;
+ }
+
+ applyFunctionModifications(metaFunc);
+
+ setInclude(funcEntry, func->fileName());
+ if (metaFunc->typeEntry())
+ delete metaFunc->typeEntry();
+
+ metaFunc->setTypeEntry(funcEntry);
+ m_globalFunctions << metaFunc;
+ }
+
+ ReportHandler::setProgressReference(m_metaClasses);
+ for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) {
+ ReportHandler::progress(QLatin1String("Fixing class inheritance..."));
+ if (!cls->isInterface() && !cls->isNamespace())
+ setupInheritance(cls);
+ }
+
+ ReportHandler::setProgressReference(m_metaClasses);
+ for (AbstractMetaClass *cls : qAsConst(m_metaClasses)) {
+ ReportHandler::progress(QLatin1String("Detecting inconsistencies in class model..."));
+ cls->fixFunctions();
+
+ if (!cls->typeEntry()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("class '%1' does not have an entry in the type system")
+ .arg(cls->name());
+ } else {
+ bool couldAddDefaultCtors = !cls->isFinalInCpp() && !cls->isInterface() && !cls->isNamespace();
+ if (couldAddDefaultCtors) {
+ if (!cls->hasConstructors())
+ cls->addDefaultConstructor();
+ if (cls->typeEntry()->isValue() && !cls->isAbstract() && !cls->hasCopyConstructor())
+ cls->addDefaultCopyConstructor(ancestorHasPrivateCopyConstructor(cls));
+ }
+ }
+
+ if (cls->isAbstract() && !cls->isInterface())
+ cls->typeEntry()->setLookupName(cls->typeEntry()->targetLangName() + QLatin1String("$ConcreteWrapper"));
+ }
+ const TypeEntryHash allEntries = types->allEntries();
+ ReportHandler::progress(QLatin1String("Detecting inconsistencies in typesystem..."));
+ for (TypeEntryHash::const_iterator it = allEntries.cbegin(), end = allEntries.cend(); it != end; ++it) {
+ for (TypeEntry *entry : it.value()) {
+ if (entry->isPrimitive())
+ continue;
+
+ if ((entry->isValue() || entry->isObject())
+ && !entry->isString()
+ && !entry->isChar()
+ && !entry->isContainer()
+ && !entry->isCustom()
+ && !entry->isVariant()
+ && !AbstractMetaClass::findClass(m_metaClasses, entry->qualifiedCppName())) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("type '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.")
+ .arg(entry->qualifiedCppName());
+ } else if (entry->generateCode() && entry->type() == TypeEntry::FunctionType) {
+ const FunctionTypeEntry* fte = static_cast<const FunctionTypeEntry*>(entry);
+ const QStringList &signatures = fte->signatures();
+ for (const QString &signature : signatures) {
+ bool ok = false;
+ for (AbstractMetaFunction* func : qAsConst(m_globalFunctions)) {
+ if (signature == func->minimalSignature()) {
+ ok = true;
+ break;
+ }
+ }
+ if (!ok) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Global function '%1' is specified in typesystem, but not defined. This could potentially lead to compilation errors.")
+ .arg(signature);
+ }
+ }
+ } else if (entry->isEnum()) {
+ const QString name = ((EnumTypeEntry*) entry)->targetLangQualifier();
+ AbstractMetaClass *cls = AbstractMetaClass::findClass(m_metaClasses, name);
+
+ bool enumFound = false;
+ if (cls) {
+ enumFound = cls->findEnum(entry->targetLangName());
+ } else { // Global enum
+ for (AbstractMetaEnum *metaEnum : qAsConst(m_enums)) {
+ if (metaEnum->typeEntry() == entry) {
+ enumFound = true;
+ break;
+ }
+ }
+ }
+ if (!enumFound) {
+ entry->setCodeGeneration(TypeEntry::GenerateNothing);
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("enum '%1' is specified in typesystem, but not declared")
+ .arg(entry->qualifiedCppName());
+ }
+
+ }
+ }
+ }
+
+ {
+ const FunctionList &hashFunctions = dom->findFunctions(QLatin1String("qHash"));
+ for (const FunctionModelItem &item : hashFunctions)
+ registerHashFunction(item);
+ }
+
+ {
+ const FunctionList &streamOps = dom->findFunctions(QLatin1String("operator<<"));
+ for (const FunctionModelItem &item : streamOps)
+ registerToStringCapability(item);
+ }
+
+ {
+ FunctionList binaryOperators = dom->findFunctions(QStringLiteral("operator=="));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator!=")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator<=")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator>=")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator<")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator+")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator/")));
+ // Filter binary operators, skipping for example
+ // class Iterator { ... Value *operator*() ... };
+ const FunctionList potentiallyBinaryOperators =
+ dom->findFunctions(QStringLiteral("operator*"))
+ + dom->findFunctions(QStringLiteral("operator&"));
+ for (const FunctionModelItem &item : potentiallyBinaryOperators) {
+ if (!item->arguments().isEmpty())
+ binaryOperators.append(item);
+ }
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator-")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator&")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator|")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator^")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator~")));
+ binaryOperators.append(dom->findFunctions(QStringLiteral("operator>")));
+
+ for (const FunctionModelItem &item : qAsConst(binaryOperators))
+ traverseOperatorFunction(item);
+ }
+
+ {
+ const FunctionList streamOperators = dom->findFunctions(QLatin1String("operator<<"))
+ + dom->findFunctions(QLatin1String("operator>>"));
+ for (const FunctionModelItem &item : streamOperators)
+ traverseStreamOperator(item);
+ }
+
+ figureOutDefaultEnumArguments();
+ checkFunctionModifications();
+
+ // sort all classes topologically
+ m_metaClasses = classesTopologicalSorted();
+
+ for (AbstractMetaClass* cls : qAsConst(m_metaClasses)) {
+// setupEquals(cls);
+// setupComparable(cls);
+ setupClonable(cls);
+ setupExternalConversion(cls);
+
+ // sort all inner classes topologically
+ if (!cls->typeEntry()->codeGeneration() || cls->innerClasses().size() < 2)
+ continue;
+
+ cls->setInnerClasses(classesTopologicalSorted(cls));
+ }
+
+ dumpLog();
+
+ sortLists();
+
+ m_currentClass = 0;
+
+ // Functions added to the module on the type system.
+ const AddedFunctionList &globalUserFunctions = types->globalUserFunctions();
+ for (const AddedFunction &addedFunc : globalUserFunctions) {
+ AbstractMetaFunction* metaFunc = traverseFunction(addedFunc);
+ metaFunc->setFunctionType(AbstractMetaFunction::NormalFunction);
+ m_globalFunctions << metaFunc;
+ }
+
+ std::puts("");
+}
+
+bool AbstractMetaBuilder::build(const QByteArrayList &arguments, unsigned clangFlags)
+{
+ const FileModelItem dom = d->buildDom(arguments, clangFlags);
+ if (dom.isNull())
+ return false;
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug))
+ qCDebug(lcShiboken) << dom.data();
+ d->traverseDom(dom);
+ return true;
+}
+
+void AbstractMetaBuilder::setLogDirectory(const QString& logDir)
+{
+ d->m_logDirectory = logDir;
+ if (!d->m_logDirectory.endsWith(QDir::separator()))
+ d->m_logDirectory.append(QDir::separator());
+}
+
+void AbstractMetaBuilderPrivate::addAbstractMetaClass(AbstractMetaClass *cls)
+{
+ if (!cls)
+ return;
+
+ cls->setOriginalAttributes(cls->attributes());
+ if (cls->typeEntry()->isContainer()) {
+ m_templates << cls;
+ } else if (cls->typeEntry()->isSmartPointer()) {
+ m_smartPointers << cls;
+ } else {
+ m_metaClasses << cls;
+ if (cls->typeEntry()->designatedInterface()) {
+ AbstractMetaClass* interface = cls->extractInterface();
+ m_metaClasses << interface;
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug))
+ qCDebug(lcShiboken) << QStringLiteral(" -> interface '%1'").arg(interface->name());
+ }
+ }
+}
+
+AbstractMetaClass *AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom,
+ const NamespaceModelItem &namespaceItem)
+{
+ QString namespaceName =
+ (!m_namespacePrefix.isEmpty() ? m_namespacePrefix + colonColon() : QString())
+ + namespaceItem->name();
+ NamespaceTypeEntry *type = TypeDatabase::instance()->findNamespaceType(namespaceName);
+
+ if (TypeDatabase::instance()->isClassRejected(namespaceName)) {
+ m_rejectedClasses.insert(namespaceName, AbstractMetaBuilder::GenerationDisabled);
+ return 0;
+ }
+
+ if (!type) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("namespace '%1' does not have a type entry").arg(namespaceName);
+ return 0;
+ }
+
+ AbstractMetaClass* metaClass = q->createMetaClass();
+ metaClass->setTypeEntry(type);
+
+ *metaClass += AbstractMetaAttributes::Public;
+
+ m_currentClass = metaClass;
+
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
+ qCDebug(lcShiboken)
+ << QStringLiteral("namespace '%1.%2'").arg(metaClass->package(), namespaceItem->name());
+ }
+
+ traverseEnums(namespaceItem, metaClass, namespaceItem->enumsDeclarations());
+
+ pushScope(namespaceItem);
+ m_namespacePrefix = currentScope()->qualifiedName().join(colonColon());
+
+ const ClassList &classes = namespaceItem->classes();
+ for (const ClassModelItem &cls : classes) {
+ AbstractMetaClass* mjc = traverseClass(dom, cls);
+ if (mjc) {
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ addAbstractMetaClass(mjc);
+ }
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ const TypeDefList typeDefs = namespaceItem->typeDefs();
+ for (const TypeDefModelItem &typeDef : typeDefs) {
+ AbstractMetaClass *cls = traverseTypeDef(dom, typeDef);
+ if (cls) {
+ metaClass->addInnerClass(cls);
+ cls->setEnclosingClass(metaClass);
+ addAbstractMetaClass(cls);
+ }
+ }
+
+ // Traverse namespaces recursively
+ const QSet<NamespaceModelItem> &innerNamespaces = namespaceItem->uniqueNamespaces();
+ for (const NamespaceModelItem &ni : innerNamespaces) {
+ AbstractMetaClass* mjc = traverseNamespace(dom, ni);
+ if (mjc) {
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ addAbstractMetaClass(mjc);
+ }
+ }
+
+ m_currentClass = 0;
+
+ popScope();
+ m_namespacePrefix = currentScope()->qualifiedName().join(colonColon());
+
+ if (!type->include().isValid())
+ setInclude(type, namespaceItem->fileName());
+
+ return metaClass;
+}
+
+struct Operator
+{
+ enum Type { Complement, Plus, ShiftRight, ShiftLeft, None };
+
+ Operator() : type(None) {}
+
+ int calculate(int x)
+ {
+ switch (type) {
+ case Complement: return ~value;
+ case Plus: return x + value;
+ case ShiftRight: return x >> value;
+ case ShiftLeft: return x << value;
+ case None: return x;
+ }
+ return x;
+ }
+
+ Type type;
+ int value;
+};
+
+
+
+Operator findOperator(QString* s)
+{
+ const char *names[] = {
+ "~",
+ "+",
+ ">>",
+ "<<"
+ };
+
+ for (int i = 0; i < Operator::None; ++i) {
+ QString name = QLatin1String(names[i]);
+ QString str = *s;
+ int splitPoint = str.indexOf(name);
+ if (splitPoint > -1) {
+ bool ok;
+ QString right = str.mid(splitPoint + name.length());
+ Operator op;
+
+ op.value = right.toInt(&ok);
+ if (!ok && right.length() > 0 && right.at(right.length() - 1).toLower() == QLatin1Char('u'))
+ op.value = right.left(right.length() - 1).toUInt(&ok, 0);
+
+ if (ok) {
+ op.type = Operator::Type(i);
+ if (splitPoint > 0)
+ *s = str.left(splitPoint).trimmed();
+ else
+ *s = QString();
+ return op;
+ }
+ }
+ }
+ return Operator();
+}
+
+int AbstractMetaBuilderPrivate::figureOutEnumValue(const QString &stringValue,
+ int oldValuevalue,
+ AbstractMetaEnum *metaEnum,
+ AbstractMetaFunction *metaFunction)
+{
+ if (stringValue.isEmpty())
+ return oldValuevalue;
+
+ QStringList stringValues = stringValue.split(QLatin1Char('|'));
+
+ int returnValue = 0;
+
+ bool matched = false;
+
+ for (int i = 0; i < stringValues.size(); ++i) {
+ QString s = stringValues.at(i).trimmed();
+
+ bool ok;
+ int v;
+
+ Operator op = findOperator(&s);
+
+ if (s.length() > 0 && s.at(0) == QLatin1Char('0'))
+ v = s.toUInt(&ok, 0);
+ else if (s.length() > 0 && s.at(s.length() - 1).toLower() == QLatin1Char('u'))
+ v = s.left(s.length() - 1).toUInt(&ok, 0);
+ else
+ v = s.toInt(&ok);
+
+ if (ok || s.isEmpty()) {
+ matched = true;
+ } else if (m_enumValues.contains(s)) {
+ v = m_enumValues[s]->value();
+ matched = true;
+ } else {
+ if (metaEnum) {
+ v = findOutValueFromString(s, matched);
+ if (!matched) {
+ QString enclosingClass = QString(metaEnum->enclosingClass() ? metaEnum->enclosingClass()->name() + colonColon() : QString());
+ qCWarning(lcShiboken).noquote().nospace()
+ << "unhandled enum value: " << s << " in "
+ << enclosingClass << metaEnum->name() << " from header '"
+ << metaEnum->typeEntry()->include().name() << '\'';
+ }
+ } else {
+ qCWarning(lcShiboken) << "unhandled enum value: Unknown enum";
+ }
+ }
+
+ if (matched)
+ returnValue |= op.calculate(v);
+ }
+
+ if (!matched) {
+ QString warn = QStringLiteral("unmatched enum %1").arg(stringValue);
+
+ if (metaFunction) {
+ warn += QStringLiteral(" when parsing default value of '%1' in class '%2'")
+ .arg(metaFunction->name(), metaFunction->implementingClass()->name());
+ }
+ warn += QLatin1String(" from header '") + metaEnum->typeEntry()->include().name()
+ + QLatin1Char('\'');
+
+ qCWarning(lcShiboken).noquote().nospace() << warn;
+ returnValue = oldValuevalue;
+ }
+
+ return returnValue;
+}
+
+void AbstractMetaBuilderPrivate::figureOutEnumValuesForClass(AbstractMetaClass *metaClass,
+ QSet<AbstractMetaClass *> *classes)
+{
+ AbstractMetaClass* base = metaClass->baseClass();
+
+ if (base && !classes->contains(base))
+ figureOutEnumValuesForClass(base, classes);
+
+ if (classes->contains(metaClass))
+ return;
+
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (AbstractMetaEnum* e : enums) {
+ if (!e) {
+ qCWarning(lcShiboken).noquote().nospace() << "bad enum in class " << metaClass->name();
+ continue;
+ }
+ AbstractMetaEnumValueList lst = e->values();
+ int value = 0;
+ for (int i = 0; i < lst.size(); ++i) {
+ value = figureOutEnumValue(lst.at(i)->stringValue(), value, e);
+ lst.at(i)->setValue(value);
+ value++;
+ }
+ }
+
+ *classes += metaClass;
+}
+
+
+void AbstractMetaBuilderPrivate::figureOutEnumValues()
+{
+ // Keep a set of classes that we already traversed. We use this to
+ // enforce that we traverse base classes prior to subclasses.
+ QSet<AbstractMetaClass*> classes;
+ for (AbstractMetaClass *c : qAsConst(m_metaClasses))
+ figureOutEnumValuesForClass(c, &classes);
+
+ for (AbstractMetaEnum* metaEnum : qAsConst(m_globalEnums)) {
+ AbstractMetaEnumValueList enumValues = metaEnum->values();
+ int value = 0;
+ for (int i = 0; i < enumValues.size(); ++i) {
+ value = figureOutEnumValue(enumValues.at(i)->stringValue(), value, metaEnum);
+ enumValues.at(i)->setValue(value);
+ value++;
+ }
+ }
+}
+
+void AbstractMetaBuilderPrivate::figureOutDefaultEnumArguments()
+{
+ for (AbstractMetaClass* metaClass : qAsConst(m_metaClasses)) {
+ const AbstractMetaFunctionList &functions = metaClass->functions();
+ for (AbstractMetaFunction* metaFunction : functions) {
+ const AbstractMetaArgumentList &arguments = metaFunction->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+ QString expr = arg->defaultValueExpression();
+ if (expr.isEmpty())
+ continue;
+
+ if (!metaFunction->replacedDefaultExpression(metaFunction->implementingClass(),
+ arg->argumentIndex() + 1).isEmpty()) {
+ continue;
+ }
+
+ arg->setDefaultValueExpression(expr);
+ }
+ }
+ }
+}
+
+
+AbstractMetaEnum *AbstractMetaBuilderPrivate::traverseEnum(EnumModelItem enumItem,
+ AbstractMetaClass *enclosing,
+ const QSet<QString> &enumsDeclarations)
+{
+ QString qualifiedName = enumItem->qualifiedName().join(colonColon());
+
+ TypeEntry* typeEntry = 0;
+ if (enumItem->accessPolicy() == CodeModel::Private) {
+ QStringList names = enumItem->qualifiedName();
+ QString enumName = names.last();
+ QString nspace;
+ if (names.size() > 1)
+ nspace = QStringList(names.mid(0, names.size() - 1)).join(colonColon());
+ typeEntry = new EnumTypeEntry(nspace, enumName, 0);
+ TypeDatabase::instance()->addType(typeEntry);
+ } else if (!enumItem->isAnonymous()) {
+ typeEntry = TypeDatabase::instance()->findType(qualifiedName);
+ } else {
+ QStringList tmpQualifiedName = enumItem->qualifiedName();
+ const EnumeratorList &enums = enumItem->enumerators();
+ for (const EnumeratorModelItem& enumValue : enums) {
+ tmpQualifiedName.removeLast();
+ tmpQualifiedName << enumValue->name();
+ qualifiedName = tmpQualifiedName.join(colonColon());
+ typeEntry = TypeDatabase::instance()->findType(qualifiedName);
+ if (typeEntry)
+ break;
+ }
+ }
+
+ QString enumName = enumItem->name();
+
+ QString className;
+ if (m_currentClass)
+ className = m_currentClass->typeEntry()->qualifiedCppName();
+
+ QString rejectReason;
+ if (TypeDatabase::instance()->isEnumRejected(className, enumName, &rejectReason)) {
+ if (typeEntry)
+ typeEntry->setCodeGeneration(TypeEntry::GenerateNothing);
+ m_rejectedEnums.insert(qualifiedName + rejectReason, AbstractMetaBuilder::GenerationDisabled);
+ return 0;
+ }
+
+ if (!typeEntry || !typeEntry->isEnum()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("enum '%1' does not have a type entry or is not an enum")
+ .arg(qualifiedName);
+ m_rejectedEnums.insert(qualifiedName, AbstractMetaBuilder::NotInTypeSystem);
+ return 0;
+ }
+
+ AbstractMetaEnum *metaEnum = q->createMetaEnum();
+ if (enumsDeclarations.contains(qualifiedName)
+ || enumsDeclarations.contains(enumName)) {
+ metaEnum->setHasQEnumsDeclaration(true);
+ }
+
+ metaEnum->setTypeEntry((EnumTypeEntry*) typeEntry);
+ switch (enumItem->accessPolicy()) {
+ case CodeModel::Public:
+ *metaEnum += AbstractMetaAttributes::Public;
+ break;
+ case CodeModel::Protected:
+ *metaEnum += AbstractMetaAttributes::Protected;
+ break;
+ case CodeModel::Private:
+ *metaEnum += AbstractMetaAttributes::Private;
+ typeEntry->setCodeGeneration(TypeEntry::GenerateNothing);
+ break;
+ default:
+ break;
+ }
+
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug))
+ qCDebug(lcShiboken) << " - traversing enum " << metaEnum->fullName();
+
+ const EnumeratorList &enums = enumItem->enumerators();
+ for (const EnumeratorModelItem &value : enums) {
+
+ AbstractMetaEnumValue *metaEnumValue = q->createMetaEnumValue();
+ metaEnumValue->setName(value->name());
+ // Deciding the enum value...
+
+ metaEnumValue->setStringValue(value->value());
+ metaEnum->addEnumValue(metaEnumValue);
+
+ if (ReportHandler::isDebug(ReportHandler::FullDebug)) {
+ qCDebug(lcShiboken) << " - " << metaEnumValue->name() << " = "
+ << metaEnumValue->value() << " = " << metaEnumValue->value();
+ }
+
+ // Add into global register...
+ if (enclosing)
+ m_enumValues[enclosing->name() + colonColon() + metaEnumValue->name()] = metaEnumValue;
+ else
+ m_enumValues[metaEnumValue->name()] = metaEnumValue;
+ }
+
+ m_enums << metaEnum;
+
+ if (!metaEnum->typeEntry()->include().isValid())
+ setInclude(metaEnum->typeEntry(), enumItem->fileName());
+
+ metaEnum->setOriginalAttributes(metaEnum->attributes());
+
+ // Register all enum values on Type database
+ const EnumeratorList &enumerators = enumItem->enumerators();
+ for (EnumeratorModelItem e : enumItem->enumerators()) {
+ QString name;
+ if (enclosing) {
+ name += enclosing->name();
+ name += colonColon();
+ }
+ name += e->name();
+ EnumValueTypeEntry* enumValue = new EnumValueTypeEntry(name, e->value(), static_cast<EnumTypeEntry*>(typeEntry), typeEntry->version());
+ TypeDatabase::instance()->addType(enumValue);
+ }
+
+ return metaEnum;
+}
+
+AbstractMetaClass* AbstractMetaBuilderPrivate::traverseTypeDef(const FileModelItem &dom,
+ const TypeDefModelItem &typeDef)
+{
+ TypeDatabase* types = TypeDatabase::instance();
+ QString className = stripTemplateArgs(typeDef->name());
+
+ QString fullClassName = className;
+ // we have an inner class
+ if (m_currentClass) {
+ fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName())
+ + colonColon() + fullClassName;
+ }
+
+ // If this is the alias for a primitive type
+ // we store the aliased type on the alias
+ // TypeEntry
+ PrimitiveTypeEntry* ptype = types->findPrimitiveType(className);
+ if (ptype) {
+ QString typeDefName = typeDef->type().qualifiedName()[0];
+ ptype->setReferencedTypeEntry(types->findPrimitiveType(typeDefName));
+ return 0;
+ }
+
+
+ // If we haven't specified anything for the typedef, then we don't care
+ ComplexTypeEntry* type = types->findComplexType(fullClassName);
+ if (!type)
+ return 0;
+
+ if (type->isObject())
+ static_cast<ObjectTypeEntry *>(type)->setQObject(isQObject(dom, stripTemplateArgs(typeDef->type().qualifiedName().join(colonColon()))));
+
+ AbstractMetaClass *metaClass = q->createMetaClass();
+ metaClass->setTypeDef(true);
+ metaClass->setTypeEntry(type);
+ metaClass->setBaseClassNames(QStringList() << typeDef->type().qualifiedName().join(colonColon()));
+ *metaClass += AbstractMetaAttributes::Public;
+
+ // Set the default include file name
+ if (!type->include().isValid())
+ setInclude(type, typeDef->fileName());
+
+ fillAddedFunctions(metaClass);
+
+ return metaClass;
+}
+
+AbstractMetaClass *AbstractMetaBuilderPrivate::traverseClass(const FileModelItem &dom,
+ const ClassModelItem &classItem)
+{
+ QString className = stripTemplateArgs(classItem->name());
+ QString fullClassName = className;
+
+ // we have inner an class
+ if (m_currentClass) {
+ fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName())
+ + colonColon() + fullClassName;
+ }
+
+ ComplexTypeEntry* type = TypeDatabase::instance()->findComplexType(fullClassName);
+ AbstractMetaBuilder::RejectReason reason = AbstractMetaBuilder::NoReason;
+
+ if (fullClassName == QLatin1String("QMetaTypeId")) {
+ // QtScript: record which types have been declared
+ int lpos = classItem->name().indexOf(QLatin1Char('<'));
+ int rpos = classItem->name().lastIndexOf(QLatin1Char('>'));
+ if ((lpos != -1) && (rpos != -1)) {
+ QString declaredTypename = classItem->name().mid(lpos + 1, rpos - lpos - 1);
+ m_qmetatypeDeclaredTypenames.insert(declaredTypename);
+ }
+ }
+
+ if (TypeDatabase::instance()->isClassRejected(fullClassName)) {
+ reason = AbstractMetaBuilder::GenerationDisabled;
+ } else if (!type) {
+ TypeEntry *te = TypeDatabase::instance()->findType(fullClassName);
+ if (te && !te->isComplex())
+ reason = AbstractMetaBuilder::RedefinedToNotClass;
+ else
+ reason = AbstractMetaBuilder::NotInTypeSystem;
+ } else if (type->codeGeneration() == TypeEntry::GenerateNothing) {
+ reason = AbstractMetaBuilder::GenerationDisabled;
+ }
+ if (reason != AbstractMetaBuilder::NoReason) {
+ m_rejectedClasses.insert(fullClassName, reason);
+ return 0;
+ }
+
+ if (type->isObject())
+ ((ObjectTypeEntry*)type)->setQObject(isQObject(dom, fullClassName));
+
+ AbstractMetaClass *metaClass = q->createMetaClass();
+ metaClass->setTypeEntry(type);
+ metaClass->setBaseClassNames(classItem->baseClasses());
+ *metaClass += AbstractMetaAttributes::Public;
+ if (type->stream())
+ metaClass->setStream(true);
+
+ AbstractMetaClass* oldCurrentClass = m_currentClass;
+ m_currentClass = metaClass;
+
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
+ const QString message = type->isContainer()
+ ? QStringLiteral("container: '%1'").arg(fullClassName)
+ : QStringLiteral("class: '%1'").arg(metaClass->fullName());
+ qCDebug(lcShiboken) << message;
+ }
+
+ TemplateParameterList template_parameters = classItem->templateParameters();
+ QVector<TypeEntry *> template_args;
+ template_args.clear();
+ for (int i = 0; i < template_parameters.size(); ++i) {
+ const TemplateParameterModelItem &param = template_parameters.at(i);
+ TemplateArgumentEntry *param_type = new TemplateArgumentEntry(param->name(), type->version());
+ param_type->setOrdinal(i);
+ template_args.append(param_type);
+ }
+ metaClass->setTemplateArguments(template_args);
+
+ parseQ_Property(metaClass, classItem->propertyDeclarations());
+
+ traverseEnums(classItem, metaClass, classItem->enumsDeclarations());
+
+ // Inner classes
+ {
+ const ClassList &innerClasses = classItem->classes();
+ for (const ClassModelItem &ci : innerClasses) {
+ AbstractMetaClass *cl = traverseClass(dom, ci);
+ if (cl) {
+ cl->setEnclosingClass(metaClass);
+ metaClass->addInnerClass(cl);
+ m_metaClasses << cl;
+ }
+ }
+
+ }
+
+ // Go through all typedefs to see if we have defined any
+ // specific typedefs to be used as classes.
+ const TypeDefList typeDefs = classItem->typeDefs();
+ for (const TypeDefModelItem &typeDef : typeDefs) {
+ AbstractMetaClass *cls = traverseTypeDef(dom, typeDef);
+ if (cls) {
+ cls->setEnclosingClass(metaClass);
+ addAbstractMetaClass(cls);
+ }
+ }
+
+
+ m_currentClass = oldCurrentClass;
+
+ // Set the default include file name
+ if (!type->include().isValid())
+ setInclude(type, classItem->fileName());
+
+ return metaClass;
+}
+
+void AbstractMetaBuilderPrivate::traverseScopeMembers(ScopeModelItem item,
+ AbstractMetaClass *metaClass)
+{
+ // Classes/Namespace members
+ traverseFields(item, metaClass);
+ traverseFunctions(item, metaClass);
+
+ // Inner classes
+ const ClassList &innerClasses = item->classes();
+ for (const ClassModelItem& ci : innerClasses)
+ traverseClassMembers(ci);
+}
+
+AbstractMetaClass* AbstractMetaBuilderPrivate::currentTraversedClass(ScopeModelItem item)
+{
+ QString className = stripTemplateArgs(item->name());
+ QString fullClassName = className;
+
+ // This is an inner class
+ if (m_currentClass)
+ fullClassName = stripTemplateArgs(m_currentClass->typeEntry()->qualifiedCppName()) + colonColon() + fullClassName;
+
+ AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, fullClassName);
+ if (!metaClass)
+ metaClass = AbstractMetaClass::findClass(m_templates, fullClassName);
+
+ if (!metaClass)
+ metaClass = AbstractMetaClass::findClass(m_smartPointers, fullClassName);
+ return metaClass;
+}
+
+void AbstractMetaBuilderPrivate::traverseClassMembers(ClassModelItem item)
+{
+ AbstractMetaClass* metaClass = currentTraversedClass(item);
+ if (!metaClass)
+ return;
+
+ AbstractMetaClass* oldCurrentClass = m_currentClass;
+ m_currentClass = metaClass;
+
+ // Class members
+ traverseScopeMembers(item, metaClass);
+
+ m_currentClass = oldCurrentClass;
+}
+
+void AbstractMetaBuilderPrivate::traverseNamespaceMembers(NamespaceModelItem item)
+{
+ AbstractMetaClass* metaClass = currentTraversedClass(item);
+ if (!metaClass)
+ return;
+
+ AbstractMetaClass* oldCurrentClass = m_currentClass;
+ m_currentClass = metaClass;
+
+ // Namespace members
+ traverseScopeMembers(item, metaClass);
+
+ // Inner namespaces
+ const QSet<NamespaceModelItem> &innerNamespaces = item->uniqueNamespaces();
+ for (const NamespaceModelItem &ni : innerNamespaces)
+ traverseNamespaceMembers(ni);
+
+ m_currentClass = oldCurrentClass;
+}
+
+static inline QString fieldSignatureWithType(VariableModelItem field)
+{
+ return field->name() + QStringLiteral(" -> ") + field->type().toString();
+}
+
+static inline QString qualifiedFieldSignatureWithType(const QString &className,
+ VariableModelItem field)
+{
+ return className + colonColon() + fieldSignatureWithType(field);
+}
+
+AbstractMetaField *AbstractMetaBuilderPrivate::traverseField(VariableModelItem field,
+ const AbstractMetaClass *cls)
+{
+ QString fieldName = field->name();
+ QString className = m_currentClass->typeEntry()->qualifiedCppName();
+
+ // Ignore friend decl.
+ if (field->isFriend())
+ return 0;
+
+ if (field->accessPolicy() == CodeModel::Private)
+ return 0;
+
+ QString rejectReason;
+ if (TypeDatabase::instance()->isFieldRejected(className, fieldName, &rejectReason)) {
+ m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field) + rejectReason,
+ AbstractMetaBuilder::GenerationDisabled);
+ return 0;
+ }
+
+
+ AbstractMetaField *metaField = q->createMetaField();
+ metaField->setName(fieldName);
+ metaField->setEnclosingClass(cls);
+
+ bool ok;
+ TypeInfo fieldType = field->type();
+ AbstractMetaType *metaType = translateType(fieldType, &ok);
+
+ if (!metaType || !ok) {
+ const QString type = TypeInfo::resolveType(fieldType, currentScope()).qualifiedName().join(colonColon());
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("skipping field '%1::%2' with unmatched type '%3'")
+ .arg(m_currentClass->name(), fieldName, type);
+ delete metaField;
+ return 0;
+ }
+
+ metaField->setType(metaType);
+
+ AbstractMetaAttributes::Attributes attr = 0;
+ if (field->isStatic())
+ attr |= AbstractMetaAttributes::Static;
+
+ CodeModel::AccessPolicy policy = field->accessPolicy();
+ if (policy == CodeModel::Public)
+ attr |= AbstractMetaAttributes::Public;
+ else if (policy == CodeModel::Protected)
+ attr |= AbstractMetaAttributes::Protected;
+ else
+ attr |= AbstractMetaAttributes::Private;
+ metaField->setAttributes(attr);
+
+ return metaField;
+}
+
+void AbstractMetaBuilderPrivate::traverseFields(ScopeModelItem scope_item,
+ AbstractMetaClass *metaClass)
+{
+ const VariableList &variables = scope_item->variables();
+ for (const VariableModelItem &field : variables) {
+ AbstractMetaField* metaField = traverseField(field, metaClass);
+
+ if (metaField && !metaField->isModifiedRemoved()) {
+ metaField->setOriginalAttributes(metaField->attributes());
+ metaClass->addField(metaField);
+ }
+ }
+}
+
+void AbstractMetaBuilderPrivate::setupFunctionDefaults(AbstractMetaFunction *metaFunction,
+ AbstractMetaClass *metaClass)
+{
+ // Set the default value of the declaring class. This may be changed
+ // in fixFunctions later on
+ metaFunction->setDeclaringClass(metaClass);
+
+ // Some of the queries below depend on the implementing class being set
+ // to function properly. Such as function modifications
+ metaFunction->setImplementingClass(metaClass);
+
+ if (metaFunction->name() == QLatin1String("operator_equal"))
+ metaClass->setHasEqualsOperator(true);
+
+ if (!metaFunction->isFinalInTargetLang()
+ && metaFunction->isRemovedFrom(metaClass, TypeSystem::TargetLangCode)) {
+ *metaFunction += AbstractMetaAttributes::FinalInCpp;
+ }
+}
+
+void AbstractMetaBuilderPrivate::fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction)
+{
+ if (!metaFunction->isConversionOperator())
+ return;
+
+ TypeDatabase* types = TypeDatabase::instance();
+ static const QRegularExpression operatorRegExp(QStringLiteral("^operator "));
+ Q_ASSERT(operatorRegExp.isValid());
+ QString castTo = metaFunction->name().remove(operatorRegExp).trimmed();
+
+ if (castTo.endsWith(QLatin1Char('&')))
+ castTo.chop(1);
+ if (castTo.startsWith(QLatin1String("const ")))
+ castTo.remove(0, 6);
+
+ TypeEntry* retType = types->findType(castTo);
+ if (!retType)
+ return;
+
+ AbstractMetaType* metaType = q->createMetaType();
+ metaType->setTypeEntry(retType);
+ metaFunction->replaceType(metaType);
+}
+
+static bool _compareAbstractMetaTypes(const AbstractMetaType* type, const AbstractMetaType* other)
+{
+ if (!type && !other)
+ return true;
+ if (!type || !other)
+ return false;
+ return type->typeEntry() == other->typeEntry()
+ && type->isConstant() == other->isConstant()
+ && type->referenceType() == other->referenceType()
+ && type->indirections() == other->indirections();
+}
+
+static bool _compareAbstractMetaFunctions(const AbstractMetaFunction* func, const AbstractMetaFunction* other)
+{
+ if (!func && !other)
+ return true;
+ if (!func || !other)
+ return false;
+ if (func->arguments().count() != other->arguments().count()
+ || func->isConstant() != other->isConstant()
+ || func->isStatic() != other->isStatic()
+ || !_compareAbstractMetaTypes(func->type(), other->type())) {
+ return false;
+ }
+ for (int i = 0; i < func->arguments().count(); ++i) {
+ if (!_compareAbstractMetaTypes(func->arguments().at(i)->type(), other->arguments().at(i)->type()))
+ return false;
+ }
+ return true;
+}
+
+// Fix the arguments of template classes that take the class itself, for example:
+// "QList(const QList &)" to "QList(const QList<T> &)".
+static bool _fixFunctionModelItemTypes(FunctionModelItem& function, const AbstractMetaClass* metaClass)
+{
+ const QVector<TypeEntry *> &templateTypes = metaClass->templateArguments();
+ if (templateTypes.isEmpty())
+ return false;
+
+ const QStringList classType = metaClass->typeEntry()->qualifiedCppName().split(colonColon());
+ QStringList fixedClassType = classType;
+ fixedClassType.last().append(QLatin1Char('<'));
+ for (int i = 0, count = templateTypes.size(); i < count; ++i) {
+ if (i)
+ fixedClassType.last().append(QLatin1String(", "));
+ fixedClassType.last().append(templateTypes.at(i)->qualifiedCppName());
+ }
+ fixedClassType.last().append(QLatin1String(" >"));
+
+ bool templateTypeFixed = false;
+ TypeInfo functionType = function->type();
+ if (functionType.qualifiedName() == classType) {
+ templateTypeFixed = true;
+ functionType.setQualifiedName(fixedClassType);
+ function->setType(functionType);
+ }
+
+ ArgumentList arguments = function->arguments();
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+ TypeInfo type = arg->type();
+ if (type.qualifiedName() == classType) {
+ type.setQualifiedName(fixedClassType);
+ arg->setType(type);
+ templateTypeFixed = true;
+ }
+ }
+ return templateTypeFixed;
+}
+
+AbstractMetaFunctionList AbstractMetaBuilderPrivate::classFunctionList(const ScopeModelItem &scopeItem)
+{
+ AbstractMetaFunctionList result;
+ const FunctionList &scopeFunctionList = scopeItem->functions();
+ result.reserve(scopeFunctionList.size());
+ for (const FunctionModelItem &function : scopeFunctionList) {
+ if (AbstractMetaFunction *metaFunction = traverseFunction(function))
+ result.append(metaFunction);
+ }
+ return result;
+}
+
+// For template classes, entries with more specific types may exist from out-of-
+// line definitions. If there is a declaration which matches it after fixing
+// the parameters, remove it as duplicate. For example:
+// template class<T> Vector { public:
+// Vector(const Vector &rhs);
+// };
+// template class<T>
+// Vector<T>::Vector(const Vector<T>&) {} // More specific, remove declaration.
+
+class DuplicatingFunctionPredicate : public std::unary_function<bool, const AbstractMetaFunction *> {
+public:
+ explicit DuplicatingFunctionPredicate(const AbstractMetaFunction *f) : m_function(f) {}
+
+ bool operator()(const AbstractMetaFunction *rhs) const
+ {
+ return rhs != m_function && rhs->name() == m_function->name()
+ && _compareAbstractMetaFunctions(m_function, rhs);
+ }
+
+private:
+ const AbstractMetaFunction *m_function;
+};
+
+AbstractMetaFunctionList AbstractMetaBuilderPrivate::templateClassFunctionList(const ScopeModelItem &scopeItem,
+ AbstractMetaClass *metaClass)
+{
+ AbstractMetaFunctionList result;
+ AbstractMetaFunctionList unchangedFunctions;
+
+ const FunctionList &scopeFunctionList = scopeItem->functions();
+ result.reserve(scopeFunctionList.size());
+ unchangedFunctions.reserve(scopeFunctionList.size());
+ for (FunctionModelItem function : scopeFunctionList) {
+ // This fixes method's arguments and return types that are templates
+ // but the template variable wasn't declared in the C++ header.
+ const bool templateTypeFixed =_fixFunctionModelItemTypes(function, metaClass);
+ if (AbstractMetaFunction *metaFunction = traverseFunction(function)) {
+ result.append(metaFunction);
+ if (!templateTypeFixed)
+ unchangedFunctions.append(metaFunction);
+ }
+ }
+
+ const AbstractMetaFunctionList::ConstIterator unchangedBegin = unchangedFunctions.begin();
+ const AbstractMetaFunctionList::ConstIterator unchangedEnd = unchangedFunctions.end();
+ for (int i = result.size() - 1; i >= 0; --i) {
+ AbstractMetaFunction *function = result.at(i);
+ if (!unchangedFunctions.contains(function)
+ && unchangedEnd != std::find_if(unchangedBegin, unchangedEnd, DuplicatingFunctionPredicate(function))) {
+ delete result.takeAt(i);
+ }
+ }
+ return result;
+}
+
+void AbstractMetaBuilderPrivate::traverseFunctions(ScopeModelItem scopeItem,
+ AbstractMetaClass *metaClass)
+{
+
+ const AbstractMetaFunctionList functions = metaClass->templateArguments().isEmpty()
+ ? classFunctionList(scopeItem)
+ : templateClassFunctionList(scopeItem, metaClass);
+
+ for (AbstractMetaFunction *metaFunction : functions){
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ if (metaClass->isNamespace())
+ *metaFunction += AbstractMetaAttributes::Static;
+
+ QPropertySpec *read = 0;
+ if (!metaFunction->isSignal() && (read = metaClass->propertySpecForRead(metaFunction->name()))) {
+ // Property reader must be in the form "<type> name()"
+ if (metaFunction->type() && (read->type() == metaFunction->type()->typeEntry()) && (metaFunction->arguments().size() == 0)) {
+ *metaFunction += AbstractMetaAttributes::PropertyReader;
+ metaFunction->setPropertySpec(read);
+ }
+ } else if (QPropertySpec* write = metaClass->propertySpecForWrite(metaFunction->name())) {
+ // Property setter must be in the form "void name(<type>)"
+ // make sure the function was created with all aguments, some argument can be missing during the pareser because of errors on typesystem
+ if ((!metaFunction->type()) && (metaFunction->arguments().size() == 1) && (write->type() == metaFunction->arguments().at(0)->type()->typeEntry())) {
+ *metaFunction += AbstractMetaAttributes::PropertyWriter;
+ metaFunction->setPropertySpec(write);
+ }
+ } else if (QPropertySpec* reset = metaClass->propertySpecForReset(metaFunction->name())) {
+ // Property resetter must be in the form "void name()"
+ if ((!metaFunction->type()) && (metaFunction->arguments().size() == 0)) {
+ *metaFunction += AbstractMetaAttributes::PropertyResetter;
+ metaFunction->setPropertySpec(reset);
+ }
+ }
+
+ const bool isInvalidDestructor = metaFunction->isDestructor() && metaFunction->isPrivate();
+ const bool isInvalidConstructor = metaFunction->isConstructor()
+ && ((metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)
+ || metaFunction->isInvalid());
+ if ((isInvalidDestructor || isInvalidConstructor)
+ && !metaClass->hasNonPrivateConstructor()) {
+ *metaClass += AbstractMetaAttributes::Final;
+ } else if (metaFunction->isConstructor() && !metaFunction->isPrivate()) {
+ *metaClass -= AbstractMetaAttributes::Final;
+ metaClass->setHasNonPrivateConstructor(true);
+ }
+
+ // Classes with virtual destructors should always have a shell class
+ // (since we aren't registering the destructors, we need this extra check)
+ if (metaFunction->isDestructor() && !metaFunction->isFinal())
+ metaClass->setForceShellClass(true);
+
+ if (!metaFunction->isDestructor()
+ && !metaFunction->isInvalid()
+ && !(metaFunction->isPrivate() && metaFunction->functionType() == AbstractMetaFunction::ConstructorFunction)) {
+
+ setupFunctionDefaults(metaFunction, metaClass);
+
+ if (metaFunction->isSignal() && metaClass->hasSignal(metaFunction)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("signal '%1' in class '%2' is overloaded.")
+ .arg(metaFunction->name(), metaClass->name());
+ }
+
+ if (metaFunction->isSignal() && !metaClass->isQObject()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("signal '%1' in non-QObject class '%2'")
+ .arg(metaFunction->name(), metaClass->name());
+ }
+
+ if (metaFunction->isConversionOperator())
+ fixReturnTypeOfConversionOperator(metaFunction);
+
+ metaClass->addFunction(metaFunction);
+ applyFunctionModifications(metaFunction);
+ } else if (metaFunction->isDestructor()) {
+ metaClass->setHasPrivateDestructor(metaFunction->isPrivate());
+ metaClass->setHasProtectedDestructor(metaFunction->isProtected());
+ metaClass->setHasVirtualDestructor(metaFunction->isVirtual());
+ }
+ if (!metaFunction->ownerClass()) {
+ delete metaFunction;
+ metaFunction = 0;
+ }
+ }
+
+ fillAddedFunctions(metaClass);
+}
+
+void AbstractMetaBuilderPrivate::fillAddedFunctions(AbstractMetaClass *metaClass)
+{
+ // Add the functions added by the typesystem
+ const AddedFunctionList &addedFunctions = metaClass->typeEntry()->addedFunctions();
+ for (const AddedFunction &addedFunc : addedFunctions)
+ traverseFunction(addedFunc, metaClass);
+}
+
+void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction *func)
+{
+ const FunctionModificationList &mods = func->modifications(func->implementingClass());
+ AbstractMetaFunction& funcRef = *func;
+ for (const FunctionModification &mod : mods) {
+ if (mod.isRenameModifier()) {
+ func->setOriginalName(func->name());
+ func->setName(mod.renamedTo());
+ } else if (mod.isAccessModifier()) {
+ funcRef -= AbstractMetaAttributes::Public;
+ funcRef -= AbstractMetaAttributes::Protected;
+ funcRef -= AbstractMetaAttributes::Private;
+ funcRef -= AbstractMetaAttributes::Friendly;
+
+ if (mod.isPublic())
+ funcRef += AbstractMetaAttributes::Public;
+ else if (mod.isProtected())
+ funcRef += AbstractMetaAttributes::Protected;
+ else if (mod.isPrivate())
+ funcRef += AbstractMetaAttributes::Private;
+ else if (mod.isFriendly())
+ funcRef += AbstractMetaAttributes::Friendly;
+ }
+
+ if (mod.isFinal())
+ funcRef += AbstractMetaAttributes::FinalInTargetLang;
+ else if (mod.isNonFinal())
+ funcRef -= AbstractMetaAttributes::FinalInTargetLang;
+ }
+}
+
+bool AbstractMetaBuilderPrivate::setupInheritance(AbstractMetaClass *metaClass)
+{
+ Q_ASSERT(!metaClass->isInterface());
+
+ if (m_setupInheritanceDone.contains(metaClass))
+ return true;
+
+ m_setupInheritanceDone.insert(metaClass);
+
+ QStringList baseClasses = metaClass->baseClassNames();
+
+ // we only support our own containers and ONLY if there is only one baseclass
+ if (baseClasses.size() == 1 && baseClasses.first().contains(QLatin1Char('<'))) {
+ TypeParser::Info info;
+ ComplexTypeEntry* baseContainerType;
+ AbstractMetaClass* templ = findTemplateClass(baseClasses.first(), metaClass, &info, &baseContainerType);
+ if (templ) {
+ setupInheritance(templ);
+ inheritTemplate(metaClass, templ, info);
+ metaClass->typeEntry()->setBaseContainerType(templ->typeEntry());
+ return true;
+ }
+
+ if (baseContainerType) {
+ // Container types are not necessarily wrapped as 'real' classes,
+ // but there may still be classes derived from them. In such case,
+ // we still need to set the base container type in order to
+ // generate correct code for type conversion checking.
+ //
+ // Additionally, we consider this case as successfully setting up
+ // inheritance.
+ metaClass->typeEntry()->setBaseContainerType(baseContainerType);
+ return true;
+ }
+
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("template baseclass '%1' of '%2' is not known")
+ .arg(baseClasses.first(), metaClass->name());
+ return false;
+ }
+
+ TypeDatabase* types = TypeDatabase::instance();
+
+ int primary = -1;
+ int primaries = 0;
+ for (int i = 0; i < baseClasses.size(); ++i) {
+
+ if (types->isClassRejected(baseClasses.at(i)))
+ continue;
+
+ TypeEntry* baseClassEntry = types->findType(baseClasses.at(i));
+ if (!baseClassEntry) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("class '%1' inherits from unknown base class '%2'")
+ .arg(metaClass->name(), baseClasses.at(i));
+ } else if (!baseClassEntry->designatedInterface()) { // true for primary base class
+ primaries++;
+ primary = i;
+ }
+ }
+
+ if (primary >= 0) {
+ AbstractMetaClass *baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClasses.at(primary));
+ if (!baseClass) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("unknown baseclass for '%1': '%2'")
+ .arg(metaClass->name(), baseClasses.at(primary));
+ return false;
+ }
+ metaClass->setBaseClass(baseClass);
+ }
+
+ for (int i = 0; i < baseClasses.size(); ++i) {
+ if (types->isClassRejected(baseClasses.at(i)))
+ continue;
+
+ if (i != primary) {
+ AbstractMetaClass *baseClass = AbstractMetaClass::findClass(m_metaClasses, baseClasses.at(i));
+ if (!baseClass) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("class not found for setup inheritance '%1'").arg(baseClasses.at(i));
+ return false;
+ }
+
+ setupInheritance(baseClass);
+
+ QString interfaceName = baseClass->isInterface() ? InterfaceTypeEntry::interfaceName(baseClass->name()) : baseClass->name();
+ AbstractMetaClass *iface = AbstractMetaClass::findClass(m_metaClasses, interfaceName);
+ if (!iface) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("unknown interface for '%1': '%2'").arg(metaClass->name(), interfaceName);
+ return false;
+ }
+ metaClass->addInterface(iface);
+
+ const AbstractMetaClassList &interfaces = iface->interfaces();
+ for (AbstractMetaClass* iface : interfaces)
+ metaClass->addInterface(iface);
+ }
+ }
+
+ return true;
+}
+
+void AbstractMetaBuilderPrivate::traverseEnums(ScopeModelItem scopeItem,
+ AbstractMetaClass *metaClass,
+ const QStringList &enumsDeclarations)
+{
+ const EnumList &enums = scopeItem->enums();
+ for (const EnumModelItem &enumItem : enums) {
+ AbstractMetaEnum* metaEnum = traverseEnum(enumItem, metaClass, QSet<QString>::fromList(enumsDeclarations));
+ if (metaEnum) {
+ metaClass->addEnum(metaEnum);
+ metaEnum->setEnclosingClass(metaClass);
+ }
+ }
+}
+
+AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunction& addedFunc)
+{
+ return traverseFunction(addedFunc, 0);
+}
+
+AbstractMetaFunction* AbstractMetaBuilderPrivate::traverseFunction(const AddedFunction& addedFunc,
+ AbstractMetaClass *metaClass)
+{
+ AbstractMetaFunction *metaFunction = q->createMetaFunction();
+ metaFunction->setConstant(addedFunc.isConstant());
+ metaFunction->setName(addedFunc.name());
+ metaFunction->setOriginalName(addedFunc.name());
+ AbstractMetaClass::Attributes visibility =
+ addedFunc.access() == AddedFunction::Public
+ ? AbstractMetaAttributes::Public : AbstractMetaAttributes::Protected;
+ metaFunction->setVisibility(visibility);
+ metaFunction->setUserAdded(true);
+ AbstractMetaAttributes::Attribute isStatic = addedFunc.isStatic() ? AbstractMetaFunction::Static : AbstractMetaFunction::None;
+ metaFunction->setAttributes(metaFunction->attributes() | AbstractMetaAttributes::Final | isStatic);
+ metaFunction->setType(translateType(addedFunc.version(), addedFunc.returnType()));
+
+
+ QVector<AddedFunction::TypeInfo> args = addedFunc.arguments();
+ AbstractMetaArgumentList metaArguments;
+
+ for (int i = 0; i < args.count(); ++i) {
+ AddedFunction::TypeInfo& typeInfo = args[i];
+ AbstractMetaArgument *metaArg = q->createMetaArgument();
+ AbstractMetaType* type = translateType(addedFunc.version(), typeInfo);
+ decideUsagePattern(type);
+ metaArg->setType(type);
+ metaArg->setArgumentIndex(i);
+ metaArg->setDefaultValueExpression(typeInfo.defaultValue);
+ metaArg->setOriginalDefaultValueExpression(typeInfo.defaultValue);
+ metaArguments.append(metaArg);
+ }
+
+ metaFunction->setArguments(metaArguments);
+ if (metaFunction->isOperatorOverload() && !metaFunction->isCallOperator()) {
+ if (metaArguments.size() > 2) {
+ qCWarning(lcShiboken) << "An operator overload need to have 0, 1 or 2 arguments if it's reverse.";
+ } else if (metaArguments.size() == 2) {
+ // Check if it's a reverse operator
+ if (metaArguments[1]->type()->typeEntry() == metaClass->typeEntry()) {
+ metaFunction->setReverseOperator(true);
+ // we need to call these two function to cache the old signature (with two args)
+ // we do this buggy behaviour to comply with the original apiextractor buggy behaviour.
+ metaFunction->signature();
+ metaFunction->minimalSignature();
+ metaArguments.removeLast();
+ metaFunction->setArguments(metaArguments);
+ } else {
+ qCWarning(lcShiboken) << "Operator overload can have two arguments only if it's a reverse operator!";
+ }
+ }
+ }
+
+
+ // Find the correct default values
+ for (int i = 0; i < metaArguments.size(); ++i) {
+ AbstractMetaArgument* metaArg = metaArguments.at(i);
+
+ //use relace-default-expression for set default value
+ QString replacedExpression;
+ if (m_currentClass)
+ replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
+
+ if (!replacedExpression.isEmpty()) {
+ QString expr = replacedExpression;
+ if (!metaFunction->removedDefaultExpression(m_currentClass, i + 1)) {
+ metaArg->setDefaultValueExpression(expr);
+ metaArg->setOriginalDefaultValueExpression(expr);
+
+ if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
+ m_enumDefaultArguments << QPair<AbstractMetaArgument*, AbstractMetaFunction*>(metaArg, metaFunction);
+ }
+ }
+ }
+
+ metaFunction->setOriginalAttributes(metaFunction->attributes());
+ fixArgumentNames(metaFunction);
+
+ if (metaClass) {
+ const AbstractMetaArgumentList fargs = metaFunction->arguments();
+ if (metaClass->isNamespace())
+ *metaFunction += AbstractMetaFunction::Static;
+ if (metaFunction->name() == metaClass->name()) {
+ metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ if (fargs.size() == 1) {
+ const TypeEntry *te = fargs.first()->type()->typeEntry();
+ if (te->isCustom())
+ metaFunction->setExplicit(true);
+ if (te->name() == metaFunction->name())
+ metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction);
+ }
+ } else {
+ metaFunction->setFunctionType(AbstractMetaFunction::NormalFunction);
+ }
+
+ metaFunction->setDeclaringClass(metaClass);
+ metaFunction->setImplementingClass(metaClass);
+ metaClass->addFunction(metaFunction);
+ metaClass->setHasNonPrivateConstructor(true);
+ }
+
+ return metaFunction;
+}
+
+void AbstractMetaBuilderPrivate::fixArgumentNames(AbstractMetaFunction *func)
+{
+ if (func->arguments().isEmpty())
+ return;
+ const FunctionModificationList &mods = func->modifications(m_currentClass);
+ for (const FunctionModification &mod : mods) {
+ for (const ArgumentModification &argMod : mod.argument_mods) {
+ if (!argMod.renamed_to.isEmpty()) {
+ AbstractMetaArgument* arg = func->arguments().at(argMod.index - 1);
+ arg->setOriginalName(arg->name());
+ arg->setName(argMod.renamed_to, false);
+ }
+ }
+ }
+
+ AbstractMetaArgumentList arguments = func->arguments();
+ for (int i = 0, size = arguments.size(); i < size; ++i) {
+ if (arguments.at(i)->name().isEmpty())
+ arguments[i]->setName(QLatin1String("arg__") + QString::number(i + 1), false);
+ }
+}
+
+static QString functionSignature(FunctionModelItem functionItem)
+{
+ QStringList args;
+ const ArgumentList &arguments = functionItem->arguments();
+ for (const ArgumentModelItem &arg : arguments)
+ args << arg->type().toString();
+ return functionItem->name() + QLatin1Char('(') + args.join(QLatin1Char(',')) + QLatin1Char(')');
+}
+
+static inline QString qualifiedFunctionSignatureWithType(const FunctionModelItem &functionItem,
+ const QString &className = QString())
+{
+ QString result = functionItem->type().toString() + QLatin1Char(' ');
+ if (!className.isEmpty())
+ result += className + colonColon();
+ result += functionSignature(functionItem);
+ return result;
+}
+
+static inline QString msgUnmatchedParameterType(const ArgumentModelItem &arg, int n)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "unmatched type '" << arg->type().toString() << "' in parameter #"
+ << (n + 1);
+ if (!arg->name().isEmpty())
+ str << " \"" << arg->name() << '"';
+ return result;
+}
+
+static inline QString msgVoidParameterType(const ArgumentModelItem &arg, int n)
+{
+ QString result;
+ QTextStream str(&result);
+ str << "'void' encountered at parameter #" << (n + 1);
+ if (!arg->name().isEmpty())
+ str << " \"" << arg->name() << '"';
+ return result;
+}
+
+AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModelItem functionItem)
+{
+ if (!functionItem->templateParameters().isEmpty())
+ return nullptr;
+ QString functionName = functionItem->name();
+ QString className;
+ if (m_currentClass) {
+ // Clang: Skip qt_metacast(), qt_metacall(), expanded from Q_OBJECT
+ // and overridden metaObject(), QGADGET helpers
+ if (functionName == QLatin1String("qt_check_for_QGADGET_macro")
+ || functionName.startsWith(QLatin1String("qt_meta"))) {
+ return nullptr;
+ }
+ className = m_currentClass->typeEntry()->qualifiedCppName();
+ if (functionName == QLatin1String("metaObject") && className != QLatin1String("QObject"))
+ return nullptr;
+ }
+
+ // Store original signature with unresolved typedefs for message/log purposes
+ const QString originalQualifiedSignatureWithReturn =
+ qualifiedFunctionSignatureWithType(functionItem, className);
+
+ QString rejectReason;
+ if (TypeDatabase::instance()->isFunctionRejected(className, functionName, &rejectReason)) {
+ m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
+ return 0;
+ }
+ else if (TypeDatabase::instance()->isFunctionRejected(className,
+ functionSignature(functionItem), &rejectReason)) {
+ m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
+ return 0;
+ }
+
+ Q_ASSERT(functionItem->functionType() == CodeModel::Normal
+ || functionItem->functionType() == CodeModel::Signal
+ || functionItem->functionType() == CodeModel::Slot);
+
+ if (functionItem->isFriend())
+ return 0;
+
+ AbstractMetaFunction *metaFunction = q->createMetaFunction();
+ metaFunction->setConstant(functionItem->isConstant());
+
+ if (ReportHandler::isDebug(ReportHandler::MediumDebug))
+ qCDebug(lcShiboken).noquote().nospace() << " - " << functionName << "()";
+
+ metaFunction->setName(functionName);
+ metaFunction->setOriginalName(functionItem->name());
+
+ if (functionItem->isAbstract())
+ *metaFunction += AbstractMetaAttributes::Abstract;
+
+ if (!metaFunction->isAbstract())
+ *metaFunction += AbstractMetaAttributes::Native;
+
+ if (!functionItem->isVirtual())
+ *metaFunction += AbstractMetaAttributes::Final;
+
+ if (functionItem->isInvokable())
+ *metaFunction += AbstractMetaAttributes::Invokable;
+
+ if (functionItem->isStatic()) {
+ *metaFunction += AbstractMetaAttributes::Static;
+ *metaFunction += AbstractMetaAttributes::Final;
+ }
+
+ // Access rights
+ if (functionItem->accessPolicy() == CodeModel::Public)
+ *metaFunction += AbstractMetaAttributes::Public;
+ else if (functionItem->accessPolicy() == CodeModel::Private)
+ *metaFunction += AbstractMetaAttributes::Private;
+ else
+ *metaFunction += AbstractMetaAttributes::Protected;
+
+
+ QString strippedClassName = className;
+ int cc_pos = strippedClassName.lastIndexOf(colonColon());
+ if (cc_pos > 0)
+ strippedClassName = strippedClassName.mid(cc_pos + 2);
+
+ TypeInfo functionType = functionItem->type();
+
+ if (TypeDatabase::instance()->isReturnTypeRejected(className, functionType.toString(), &rejectReason)) {
+ m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
+ delete metaFunction;
+ return nullptr;
+ }
+
+ if (functionName.startsWith(QLatin1Char('~'))) {
+ metaFunction->setFunctionType(AbstractMetaFunction::DestructorFunction);
+ metaFunction->setInvalid(true);
+ } else if (stripTemplateArgs(functionName) == strippedClassName) {
+ metaFunction->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ // Check for Copy/Move down below
+ metaFunction->setExplicit(functionItem->isExplicit());
+ metaFunction->setName(m_currentClass->name());
+ } else {
+ bool ok;
+ AbstractMetaType* type = translateType(functionType, &ok);
+
+ if (!ok) {
+ Q_ASSERT(type == 0);
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("skipping function '%1', unmatched return type '%2'")
+ .arg(originalQualifiedSignatureWithReturn,
+ functionItem->type().toString());
+ m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn, AbstractMetaBuilder::UnmatchedReturnType);
+ metaFunction->setInvalid(true);
+ return metaFunction;
+ }
+
+ metaFunction->setType(type);
+
+ if (functionItem->functionType() == CodeModel::Signal)
+ metaFunction->setFunctionType(AbstractMetaFunction::SignalFunction);
+ else if (functionItem->functionType() == CodeModel::Slot)
+ metaFunction->setFunctionType(AbstractMetaFunction::SlotFunction);
+ }
+
+ ArgumentList arguments = functionItem->arguments();
+
+ if (arguments.size() == 1) {
+ ArgumentModelItem arg = arguments.at(0);
+ TypeInfo type = arg->type();
+ if (type.qualifiedName().first() == QLatin1String("void") && type.indirections() == 0)
+ arguments.pop_front();
+ }
+
+ AbstractMetaArgumentList metaArguments;
+
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+
+ if (TypeDatabase::instance()->isArgumentTypeRejected(className, arg->type().toString(), &rejectReason)) {
+ m_rejectedFunctions.insert(originalQualifiedSignatureWithReturn + rejectReason, AbstractMetaBuilder::GenerationDisabled);
+ delete metaFunction;
+ return nullptr;
+ }
+
+ bool ok;
+ AbstractMetaType* metaType = translateType(arg->type(), &ok);
+ if (!ok) {
+ Q_ASSERT(metaType == 0);
+ const QString reason = msgUnmatchedParameterType(arg, i);
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("skipping function '%1', %2")
+ .arg(originalQualifiedSignatureWithReturn, reason);
+ const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn
+ + QLatin1String(": ") + reason;
+ m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType);
+ metaFunction->setInvalid(true);
+ return metaFunction;
+ }
+
+ if (metaType == Q_NULLPTR) {
+ const QString reason = msgVoidParameterType(arg, i);
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("skipping function '%1': %2")
+ .arg(originalQualifiedSignatureWithReturn, reason);
+ const QString rejectedFunctionSignature = originalQualifiedSignatureWithReturn
+ + QLatin1String(": ") + reason;
+ m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType);
+ metaFunction->setInvalid(true);
+ return metaFunction;
+ }
+
+ AbstractMetaArgument *metaArgument = q->createMetaArgument();
+
+ metaArgument->setType(metaType);
+ metaArgument->setName(arg->name());
+ metaArgument->setArgumentIndex(i);
+ metaArguments << metaArgument;
+ }
+
+ metaFunction->setArguments(metaArguments);
+
+ // Find the correct default values
+ for (int i = 0; i < arguments.size(); ++i) {
+ ArgumentModelItem arg = arguments.at(i);
+ AbstractMetaArgument* metaArg = metaArguments.at(i);
+
+ //use relace-default-expression for set default value
+ QString replacedExpression;
+ if (m_currentClass) {
+ replacedExpression = metaFunction->replacedDefaultExpression(m_currentClass, i + 1);
+ } else {
+ FunctionModificationList mods = TypeDatabase::instance()->functionModifications(metaFunction->minimalSignature());
+ if (!mods.isEmpty()) {
+ QVector<ArgumentModification> argMods = mods.first().argument_mods;
+ if (!argMods.isEmpty())
+ replacedExpression = argMods.first().replacedDefaultExpression;
+ }
+ }
+
+ bool hasDefaultValue = false;
+ if (arg->defaultValue() || !replacedExpression.isEmpty()) {
+ QString expr = arg->defaultValueExpression();
+ expr = fixDefaultValue(arg, metaArg->type(), metaFunction, m_currentClass, i);
+ metaArg->setOriginalDefaultValueExpression(expr);
+
+ if (metaFunction->removedDefaultExpression(m_currentClass, i + 1)) {
+ expr.clear();
+ } else if (!replacedExpression.isEmpty()) {
+ expr = replacedExpression;
+ }
+ metaArg->setDefaultValueExpression(expr);
+
+ if (metaArg->type()->isEnum() || metaArg->type()->isFlags())
+ m_enumDefaultArguments << QPair<AbstractMetaArgument *, AbstractMetaFunction *>(metaArg, metaFunction);
+
+ hasDefaultValue = !expr.isEmpty();
+ }
+
+ //Check for missing argument name
+ if (hasDefaultValue
+ && !metaArg->hasName()
+ && !metaFunction->isOperatorOverload()
+ && !metaFunction->isSignal()
+ && metaFunction->argumentName(i+1, false, m_currentClass).isEmpty()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Argument %1 on function '%2::%3' has default expression but does not have name.")
+ .arg(i+1).arg(className, metaFunction->minimalSignature());
+ }
+
+ }
+
+ fixArgumentNames(metaFunction);
+
+ // Determine class special functions
+ if (m_currentClass && metaFunction->arguments().size() == 1) {
+ const AbstractMetaType *argType = metaFunction->arguments().first()->type();
+ if (argType->typeEntry() == m_currentClass->typeEntry() && argType->indirections() == 0) {
+ if (metaFunction->isConstructor()) {
+ switch (argType->referenceType()) {
+ case NoReference:
+ metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction);
+ break;
+ case LValueReference:
+ if (argType->isConstant())
+ metaFunction->setFunctionType(AbstractMetaFunction::CopyConstructorFunction);
+ break;
+ case RValueReference:
+ metaFunction->setFunctionType(AbstractMetaFunction::MoveConstructorFunction);
+ break;
+ }
+ } else if (metaFunction->name() == QLatin1String("operator=")) {
+ switch (argType->referenceType()) {
+ case NoReference:
+ metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction);
+ break;
+ case LValueReference:
+ if (argType->isConstant())
+ metaFunction->setFunctionType(AbstractMetaFunction::AssignmentOperatorFunction);
+ break;
+ case RValueReference:
+ metaFunction->setFunctionType(AbstractMetaFunction::MoveAssignmentOperatorFunction);
+ break;
+ }
+ }
+ }
+ }
+ return metaFunction;
+}
+
+AbstractMetaType *AbstractMetaBuilderPrivate::translateType(double vr,
+ const AddedFunction::TypeInfo &typeInfo)
+{
+ Q_ASSERT(!typeInfo.name.isEmpty());
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ TypeEntry* type;
+
+ QString typeName = typeInfo.name;
+
+ if (typeName == QLatin1String("void"))
+ return 0;
+
+ type = typeDb->findType(typeName);
+
+ // test if the type is a template, like a container
+ bool isTemplate = false;
+ QStringList templateArgs;
+ if (!type && typeInfo.name.contains(QLatin1Char('<'))) {
+ const QStringList& parsedType = parseTemplateType(typeInfo.name);
+ if (parsedType.isEmpty()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Template type parsing failed for '%1'").arg(typeInfo.name);
+ } else {
+ templateArgs = parsedType.mid(1);
+ isTemplate = (type = typeDb->findContainerType(parsedType[0]));
+ }
+ }
+
+ if (!type) {
+ QStringList candidates;
+ SingleTypeEntryHash entries = typeDb->entries();
+ for (SingleTypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
+ // Let's try to find the type in different scopes.
+ if (it.key().endsWith(colonColon() + typeName))
+ candidates.append(it.key());
+ }
+
+ QString msg = QStringLiteral("Type '%1' wasn't found in the type database.\n").arg(typeName);
+
+ if (candidates.isEmpty())
+ qFatal(qPrintable(QString(msg + QLatin1String("Declare it in the type system using the proper <*-type> tag."))), NULL);
+
+ msg += QLatin1String("Remember to inform the full qualified name for the type you want to use.\nCandidates are:\n");
+ candidates.sort();
+ for (const QString& candidate : qAsConst(candidates)) {
+ msg += QLatin1String(" ") + candidate + QLatin1Char('\n');
+ }
+ qFatal(qPrintable(msg), NULL);
+ }
+
+ AbstractMetaType *metaType = q->createMetaType();
+ metaType->setTypeEntry(type);
+ metaType->setIndirections(typeInfo.indirections);
+ if (typeInfo.isReference)
+ metaType->setReferenceType(LValueReference);
+ metaType->setConstant(typeInfo.isConstant);
+ if (isTemplate) {
+ for (const QString& templateArg : qAsConst(templateArgs)) {
+ AbstractMetaType* metaArgType = translateType(vr, AddedFunction::TypeInfo::fromSignature(templateArg));
+ metaType->addInstantiation(metaArgType);
+ }
+ metaType->setTypeUsagePattern(AbstractMetaType::ContainerPattern);
+ }
+
+ return metaType;
+}
+
+static const TypeEntry* findTypeEntryUsingContext(const AbstractMetaClass* metaClass, const QString& qualifiedName)
+{
+ const TypeEntry* type = 0;
+ QStringList context = metaClass->qualifiedCppName().split(colonColon());
+ while(!type && (context.size() > 0) ) {
+ type = TypeDatabase::instance()->findType(context.join(colonColon()) + colonColon() + qualifiedName);
+ context.removeLast();
+ }
+ return type;
+}
+
+AbstractMetaType *AbstractMetaBuilderPrivate::translateType(const TypeInfo &_typei,
+ bool *ok, bool resolveType,
+ bool resolveScope)
+{
+ Q_ASSERT(ok);
+ *ok = true;
+
+ // 1. Test the type info without resolving typedefs in case this is present in the
+ // type system
+ TypeInfo typei;
+ if (resolveType) {
+ bool ok;
+ AbstractMetaType* t = translateType(_typei, &ok, false, resolveScope);
+ if (t && ok)
+ return t;
+ Q_ASSERT(t == 0);
+ }
+
+ if (!resolveType) {
+ typei = _typei;
+ } else {
+ // Go through all parts of the current scope (including global namespace)
+ // to resolve typedefs. The parser does not properly resolve typedefs in
+ // the global scope when they are referenced from inside a namespace.
+ // This is a work around to fix this bug since fixing it in resolveType
+ // seemed non-trivial
+ int i = m_scopes.size() - 1;
+ while (i >= 0) {
+ typei = TypeInfo::resolveType(_typei, m_scopes.at(i--));
+ if (typei.qualifiedName().join(colonColon()) != _typei.qualifiedName().join(colonColon()))
+ break;
+ }
+
+ }
+
+ if (typei.isFunctionPointer()) {
+ *ok = false;
+ return 0;
+ }
+
+ QString errorMessage;
+ TypeParser::Info typeInfo = TypeParser::parse(typei.toString(), &errorMessage);
+ if (typeInfo.is_busted) {
+ qWarning().noquote().nospace() << "Unable to translate type \"" << _typei.toString()
+ << "\": " << errorMessage;
+ *ok = false;
+ return 0;
+ }
+
+ // 2. Handle pointers specified as arrays with unspecified size
+ bool arrayOfUnspecifiedSize = false;
+ if (typeInfo.arrays.size() > 0) {
+ arrayOfUnspecifiedSize = true;
+ for (int i = 0; i < typeInfo.arrays.size(); ++i)
+ arrayOfUnspecifiedSize = arrayOfUnspecifiedSize && typeInfo.arrays.at(i).isEmpty();
+
+ if (!arrayOfUnspecifiedSize) {
+ TypeInfo newInfo;
+ //newInfo.setArguments(typei.arguments());
+ newInfo.setIndirections(typei.indirections());
+ newInfo.setConstant(typei.isConstant());
+ newInfo.setFunctionPointer(typei.isFunctionPointer());
+ newInfo.setQualifiedName(typei.qualifiedName());
+ newInfo.setReferenceType(typei.referenceType());
+ newInfo.setVolatile(typei.isVolatile());
+
+ AbstractMetaType* elementType = translateType(newInfo, ok);
+ if (!(*ok))
+ return 0;
+
+ for (int i = typeInfo.arrays.size() - 1; i >= 0; --i) {
+ QString s = typeInfo.arrays.at(i);
+ bool _ok;
+ int elems = findOutValueFromString(s, _ok);
+
+ AbstractMetaType *arrayType = q->createMetaType();
+ arrayType->setArrayElementCount(elems);
+ arrayType->setArrayElementType(elementType);
+ arrayType->setTypeEntry(new ArrayTypeEntry(elementType->typeEntry() , elementType->typeEntry()->version()));
+ decideUsagePattern(arrayType);
+
+ elementType = arrayType;
+ }
+
+ return elementType;
+ } else {
+ typeInfo.indirections += typeInfo.arrays.size();
+ }
+ }
+
+ QStringList qualifierList = typeInfo.qualified_name;
+ if (qualifierList.isEmpty()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("horribly broken type '%1'").arg(_typei.toString());
+ *ok = false;
+ return 0;
+ }
+
+ QString qualifiedName = qualifierList.join(colonColon());
+ QString name = qualifierList.takeLast();
+
+ // 3. Special case 'void' type
+ if (name == QLatin1String("void") && !typeInfo.indirections)
+ return 0;
+
+ // 4. Special case QFlags (include instantiation in name)
+ if (qualifiedName == QLatin1String("QFlags"))
+ qualifiedName = typeInfo.toString();
+
+ const TypeEntry *type = 0;
+ // 5. Try to find the type
+
+ // 5.1 - Try first using the current scope
+ if (m_currentClass) {
+ type = findTypeEntryUsingContext(m_currentClass, qualifiedName);
+
+ // 5.1.1 - Try using the class parents' scopes
+ if (!type && !m_currentClass->baseClassNames().isEmpty()) {
+ const AbstractMetaClassList &baseClasses = getBaseClasses(m_currentClass);
+ for (const AbstractMetaClass *cls : baseClasses) {
+ type = findTypeEntryUsingContext(cls, qualifiedName);
+ if (type)
+ break;
+ }
+ }
+ }
+
+ // 5.2 - Try without scope
+ if (!type)
+ type = TypeDatabase::instance()->findType(qualifiedName);
+
+ // 6. No? Try looking it up as a flags type
+ if (!type)
+ type = TypeDatabase::instance()->findFlagsType(qualifiedName);
+
+ // 7. No? Try looking it up as a container type
+ if (!type)
+ type = TypeDatabase::instance()->findContainerType(name);
+
+ // 8. No? Check if the current class is a template and this type is one
+ // of the parameters.
+ if (!type && m_currentClass) {
+ const QVector<TypeEntry *> &template_args = m_currentClass->templateArguments();
+ for (TypeEntry *te : template_args) {
+ if (te->name() == qualifiedName)
+ type = te;
+ }
+ }
+
+ // 9. Try finding the type by prefixing it with the current
+ // context and all baseclasses of the current context
+ if (!type && !TypeDatabase::instance()->isClassRejected(qualifiedName) && m_currentClass && resolveScope) {
+ QStringList contexts;
+ contexts.append(m_currentClass->qualifiedCppName());
+ contexts.append(currentScope()->qualifiedName().join(colonColon()));
+
+
+ TypeInfo info = typei;
+ bool subclassesDone = false;
+ while (!contexts.isEmpty() && !type) {
+ type = TypeDatabase::instance()->findType(contexts.at(0) + colonColon() + qualifiedName);
+ contexts.pop_front();
+
+ // 10. Last resort: Special cased prefix of Qt namespace since the meta object implicitly inherits this, so
+ // enum types from there may be addressed without any scope resolution in properties.
+ if (!contexts.size() && !subclassesDone) {
+ contexts << QLatin1String("Qt");
+ subclassesDone = true;
+ }
+ }
+
+ }
+
+ if (!type) {
+ *ok = false;
+ return 0;
+ }
+
+ // Used to for diagnostics later...
+ m_usedTypes << type;
+
+ // These are only implicit and should not appear in code...
+ Q_ASSERT(!type->isInterface());
+
+ AbstractMetaType *metaType = q->createMetaType();
+ metaType->setTypeEntry(type);
+ metaType->setIndirections(typeInfo.indirections);
+ metaType->setReferenceType(typeInfo.referenceType);
+ metaType->setConstant(typeInfo.is_constant);
+ metaType->setOriginalTypeDescription(_typei.toString());
+
+ for (const TypeParser::Info &ta : qAsConst(typeInfo.template_instantiations)) {
+ TypeInfo info;
+ info.setConstant(ta.is_constant);
+ info.setReferenceType(ta.referenceType);
+ info.setIndirections(ta.indirections);
+
+ info.setFunctionPointer(false);
+ info.setQualifiedName(ta.instantiationName().split(colonColon()));
+
+ AbstractMetaType* targType = translateType(info, ok);
+ if (!(*ok)) {
+ delete metaType;
+ return 0;
+ }
+
+ metaType->addInstantiation(targType, true);
+ }
+
+ // The usage pattern *must* be decided *after* the possible template
+ // instantiations have been determined, or else the absence of
+ // such instantiations will break the caching scheme of
+ // AbstractMetaType::cppSignature().
+ decideUsagePattern(metaType);
+
+ return metaType;
+}
+
+
+int AbstractMetaBuilderPrivate::findOutValueFromString(const QString &stringValue, bool &ok)
+{
+ int value = stringValue.toInt(&ok);
+ if (ok)
+ return value;
+
+ if (stringValue == QLatin1String("true") || stringValue == QLatin1String("false")) {
+ ok = true;
+ return (stringValue == QLatin1String("true"));
+ }
+
+ // This is a very lame way to handle expression evaluation,
+ // but it is not critical and will do for the time being.
+ static const QRegularExpression variableNameRegExp(QStringLiteral("^[a-zA-Z_][a-zA-Z0-9_]*$"));
+ Q_ASSERT(variableNameRegExp.isValid());
+ if (!variableNameRegExp.match(stringValue).hasMatch()) {
+ ok = true;
+ return 0;
+ }
+
+ AbstractMetaEnumValue *enumValue = AbstractMetaClass::findEnumValue(m_metaClasses, stringValue);
+ if (enumValue) {
+ ok = true;
+ return enumValue->value();
+ }
+
+ for (AbstractMetaEnum *metaEnum : qAsConst(m_globalEnums)) {
+ const AbstractMetaEnumValueList &values = metaEnum->values();
+ for (const AbstractMetaEnumValue *ev : values) {
+ if (ev->name() == stringValue) {
+ ok = true;
+ return ev->value();
+ }
+ }
+ }
+
+ ok = false;
+ return 0;
+}
+
+void AbstractMetaBuilderPrivate::decideUsagePattern(AbstractMetaType *metaType)
+{
+ metaType->decideUsagePattern();
+}
+
+QString AbstractMetaBuilderPrivate::fixDefaultValue(ArgumentModelItem item,
+ AbstractMetaType *type,
+ AbstractMetaFunction *fnc,
+ AbstractMetaClass *implementingClass,
+ int /* argumentIndex */)
+{
+ QString functionName = fnc->name();
+ QString className = implementingClass ? implementingClass->qualifiedCppName() : QString();
+
+ QString expr = item->defaultValueExpression();
+ if (type) {
+ if (type->isPrimitive()) {
+ if (type->name() == QLatin1String("boolean")) {
+ if (expr != QLatin1String("false") && expr != QLatin1String("true")) {
+ bool ok = false;
+ int number = expr.toInt(&ok);
+ if (ok && number)
+ expr = QLatin1String("true");
+ else
+ expr = QLatin1String("false");
+ }
+ } else {
+ // This can be an enum or flag so I need to delay the
+ // translation untill all namespaces are completly
+ // processed. This is done in figureOutEnumValues()
+ }
+ } else if (type->isFlags() || type->isEnum()) {
+ bool isNumber;
+ expr.toInt(&isNumber);
+ if (!isNumber && expr.indexOf(colonColon()) < 0) {
+ // Add the enum/flag scope to default value, making it usable
+ // from other contexts beside its owner class hierarchy
+ static const QRegularExpression typeRegEx(QStringLiteral("[^<]*[<]([^:]*::).*"));
+ Q_ASSERT(typeRegEx.isValid());
+ const QRegularExpressionMatch match = typeRegEx.match(type->minimalSignature());
+ if (match.hasMatch())
+ expr.prepend(match.captured(1));
+ }
+ } else if (type->isContainer() && expr.contains(QLatin1Char('<'))) {
+ static const QRegularExpression typeRegEx(QStringLiteral("[^<]*<(.*)>"));
+ Q_ASSERT(typeRegEx.isValid());
+ const QRegularExpressionMatch typeMatch = typeRegEx.match(type->minimalSignature());
+ static const QRegularExpression defaultRegEx(QLatin1String("([^<]*<).*(>[^>]*)"));
+ Q_ASSERT(defaultRegEx.isValid());
+ const QRegularExpressionMatch defaultMatch = defaultRegEx.match(expr);
+ if (typeMatch.hasMatch() && defaultMatch.hasMatch())
+ expr = defaultMatch.captured(1) + typeMatch.captured(1) + defaultMatch.captured(2);
+ } else {
+ // Here the default value is supposed to be a constructor,
+ // a class field, or a constructor receiving a class field
+ static const QRegularExpression defaultRegEx(QStringLiteral("([^\\(]*\\(|)([^\\)]*)(\\)|)"));
+ Q_ASSERT(defaultRegEx.isValid());
+ const QRegularExpressionMatch defaultMatch = defaultRegEx.match(expr);
+ QString defaultValueCtorName = defaultMatch.hasMatch() ? defaultMatch.captured(1) : QString();
+ if (defaultValueCtorName.endsWith(QLatin1Char('(')))
+ defaultValueCtorName.chop(1);
+
+ // Fix the scope for constructor using the already
+ // resolved argument type as a reference.
+ // The following regular expression extracts any
+ // use of namespaces/scopes from the type string.
+ static const QRegularExpression typeRegEx(QLatin1String("^(?:const[\\s]+|)([\\w:]*::|)([A-Za-z_]\\w*)\\s*[&\\*]?$"));
+ Q_ASSERT(typeRegEx.isValid());
+ const QRegularExpressionMatch typeMatch = typeRegEx.match(type->minimalSignature());
+
+ QString typeNamespace = typeMatch.hasMatch() ? typeMatch.captured(1) : QString();
+ QString typeCtorName = typeMatch.hasMatch() ? typeMatch.captured(2) : QString();
+ if (!typeNamespace.isEmpty() && defaultValueCtorName == typeCtorName)
+ expr.prepend(typeNamespace);
+
+ // Fix scope if the parameter is a field of the current class
+ if (implementingClass) {
+ const AbstractMetaFieldList &fields = implementingClass->fields();
+ for (const AbstractMetaField *field : fields) {
+ if (defaultMatch.hasMatch() && defaultMatch.captured(2) == field->name()) {
+ expr = defaultMatch.captured(1) + implementingClass->name()
+ + colonColon() + defaultMatch.captured(2) + defaultMatch.captured(3);
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("undefined type for default value '%3' of argument in function '%1', class '%2'")
+ .arg(functionName, className, item->defaultValueExpression());
+
+ expr = QString();
+ }
+
+ return expr;
+}
+
+bool AbstractMetaBuilderPrivate::isQObject(const FileModelItem &dom, const QString &qualifiedName)
+{
+ if (qualifiedName == QLatin1String("QObject"))
+ return true;
+
+ ClassModelItem classItem = dom->findClass(qualifiedName);
+
+ if (!classItem) {
+ QStringList names = qualifiedName.split(colonColon());
+ NamespaceModelItem ns = dom;
+ for (int i = 0; i < names.size() - 1 && ns; ++i)
+ ns = ns->findNamespace(names.at(i));
+ if (ns && names.size() >= 2)
+ classItem = ns->findClass(names.at(names.size() - 1));
+ }
+
+ bool isqobject = classItem && classItem->extendsClass(QLatin1String("QObject"));
+
+ if (classItem && !isqobject) {
+ QStringList baseClasses = classItem->baseClasses();
+ for (int i = 0; i < baseClasses.count(); ++i) {
+
+ isqobject = isQObject(dom, baseClasses.at(i));
+ if (isqobject)
+ break;
+ }
+ }
+
+ return isqobject;
+}
+
+
+bool AbstractMetaBuilderPrivate::isEnum(const FileModelItem &dom, const QStringList& qualified_name)
+{
+ CodeModelItem item = dom->model()->findItem(qualified_name, dom);
+ return item && item->kind() == _EnumModelItem::__node_kind;
+}
+
+AbstractMetaClass* AbstractMetaBuilderPrivate::findTemplateClass(const QString &name,
+ const AbstractMetaClass *context,
+ TypeParser::Info *info,
+ ComplexTypeEntry **baseContainerType) const
+{
+ TypeParser::Info localInfo;
+ if (!info)
+ info = &localInfo;
+
+ TypeDatabase* types = TypeDatabase::instance();
+
+ QStringList scope = context->typeEntry()->qualifiedCppName().split(colonColon());
+ QString errorMessage;
+ scope.removeLast();
+ for (int i = scope.size(); i >= 0; --i) {
+ QString prefix = i > 0 ? QStringList(scope.mid(0, i)).join(colonColon()) + colonColon() : QString();
+ QString completeName = prefix + name;
+ const TypeParser::Info parsed = TypeParser::parse(completeName, &errorMessage);
+ if (parsed.is_busted) {
+ qWarning().noquote().nospace() << "Unable to parse type \"" << completeName
+ << "\" while looking for template \"" << name << "\": " << errorMessage;
+ continue;
+ }
+ *info = parsed;
+ QString qualifiedName = info->qualified_name.join(colonColon());
+
+ AbstractMetaClass* templ = 0;
+ for (AbstractMetaClass *c : qAsConst(m_templates)) {
+ if (c->typeEntry()->name() == qualifiedName) {
+ templ = c;
+ break;
+ }
+ }
+
+ if (!templ)
+ templ = AbstractMetaClass::findClass(m_metaClasses, qualifiedName);
+
+ if (templ)
+ return templ;
+
+ if (baseContainerType)
+ *baseContainerType = types->findContainerType(qualifiedName);
+ }
+
+ return 0;
+}
+
+AbstractMetaClassList AbstractMetaBuilderPrivate::getBaseClasses(const AbstractMetaClass *metaClass) const
+{
+ AbstractMetaClassList baseClasses;
+ const QStringList &baseClassNames = metaClass->baseClassNames();
+ for (const QString& parent : baseClassNames) {
+ AbstractMetaClass* cls = 0;
+ if (parent.contains(QLatin1Char('<')))
+ cls = findTemplateClass(parent, metaClass);
+ else
+ cls = AbstractMetaClass::findClass(m_metaClasses, parent);
+
+ if (cls)
+ baseClasses << cls;
+ }
+ return baseClasses;
+}
+
+bool AbstractMetaBuilderPrivate::ancestorHasPrivateCopyConstructor(const AbstractMetaClass *metaClass) const
+{
+ if (metaClass->hasPrivateCopyConstructor())
+ return true;
+ const AbstractMetaClassList &baseClasses = getBaseClasses(metaClass);
+ for (const AbstractMetaClass *cls : baseClasses) {
+ if (ancestorHasPrivateCopyConstructor(cls))
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaType* AbstractMetaBuilderPrivate::inheritTemplateType(const QVector<AbstractMetaType *> &templateTypes,
+ const AbstractMetaType *metaType,
+ bool *ok)
+{
+ if (ok)
+ *ok = true;
+ if (!metaType || (!metaType->typeEntry()->isTemplateArgument() && !metaType->hasInstantiations()))
+ return metaType ? metaType->copy() : 0;
+
+ AbstractMetaType *returned = metaType->copy();
+ returned->setOriginalTemplateType(metaType->copy());
+
+ if (returned->typeEntry()->isTemplateArgument()) {
+ const TemplateArgumentEntry* tae = static_cast<const TemplateArgumentEntry*>(returned->typeEntry());
+
+ // If the template is intantiated with void we special case this as rejecting the functions that use this
+ // parameter from the instantiation.
+ if (templateTypes.size() <= tae->ordinal() || templateTypes.at(tae->ordinal())->typeEntry()->name() == QLatin1String("void")) {
+ if (ok)
+ *ok = false;
+ return 0;
+ }
+
+ AbstractMetaType* t = returned->copy();
+ t->setTypeEntry(templateTypes.at(tae->ordinal())->typeEntry());
+ t->setIndirections(templateTypes.at(tae->ordinal())->indirections() + t->indirections() ? 1 : 0);
+ decideUsagePattern(t);
+
+ delete returned;
+ returned = inheritTemplateType(templateTypes, t, ok);
+ if (ok && !(*ok))
+ return 0;
+ }
+
+ if (returned->hasInstantiations()) {
+ AbstractMetaTypeList instantiations = returned->instantiations();
+ for (int i = 0; i < instantiations.count(); ++i) {
+ AbstractMetaType *type = instantiations[i];
+ instantiations[i] = inheritTemplateType(templateTypes, type, ok);
+ if (ok && !(*ok))
+ return 0;
+ }
+ returned->setInstantiations(instantiations, true);
+ }
+
+ return returned;
+}
+
+bool AbstractMetaBuilderPrivate::inheritTemplate(AbstractMetaClass *subclass,
+ const AbstractMetaClass *templateClass,
+ const TypeParser::Info &info)
+{
+ QVector<TypeParser::Info> targs = info.template_instantiations;
+ QVector<AbstractMetaType *> templateTypes;
+
+ if (subclass->isTypeDef()) {
+ subclass->setHasCloneOperator(templateClass->hasCloneOperator());
+ subclass->setHasEqualsOperator(templateClass->hasEqualsOperator());
+ subclass->setHasHashFunction(templateClass->hasHashFunction());
+ subclass->setHasNonPrivateConstructor(templateClass->hasNonPrivateConstructor());
+ subclass->setHasPrivateDestructor(templateClass->hasPrivateDestructor());
+ subclass->setHasProtectedDestructor(templateClass->hasProtectedDestructor());
+ subclass->setHasVirtualDestructor(templateClass->hasVirtualDestructor());
+ }
+
+ for (const TypeParser::Info &i : qAsConst(targs)) {
+ QString typeName = i.qualified_name.join(colonColon());
+ QStringList possibleNames;
+ possibleNames << subclass->qualifiedCppName() + colonColon() + typeName;
+ possibleNames << templateClass->qualifiedCppName() + colonColon() + typeName;
+ if (subclass->enclosingClass())
+ possibleNames << subclass->enclosingClass()->qualifiedCppName() + colonColon() + typeName;
+ possibleNames << typeName;
+
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ TypeEntry* t = 0;
+ QString templateParamName;
+ for (const QString &possibleName : qAsConst(possibleNames)) {
+ t = typeDb->findType(possibleName);
+ if (t) {
+ QString templateParamName = possibleName;
+ break;
+ }
+ }
+
+ if (t) {
+ AbstractMetaType *temporaryType = q->createMetaType();
+ temporaryType->setTypeEntry(t);
+ temporaryType->setConstant(i.is_constant);
+ temporaryType->setReferenceType(i.referenceType);
+ temporaryType->setIndirections(i.indirections);
+ temporaryType->decideUsagePattern();
+ templateTypes << temporaryType;
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Ignoring template parameter " << templateParamName << " from "
+ << info.instantiationName() << ", because I don't know what it is.";
+ }
+ }
+
+ AbstractMetaFunctionList funcs = subclass->functions();
+ const AbstractMetaFunctionList &templateClassFunctions = templateClass->functions();
+ for (const AbstractMetaFunction *function : templateClassFunctions) {
+ if (function->isModifiedRemoved(TypeSystem::All))
+ continue;
+
+ AbstractMetaFunction *f = function->copy();
+ f->setArguments(AbstractMetaArgumentList());
+
+ bool ok = true;
+ AbstractMetaType *ftype = function->type();
+ f->replaceType(inheritTemplateType(templateTypes, ftype, &ok));
+ if (!ok) {
+ delete f;
+ continue;
+ }
+
+ const AbstractMetaArgumentList &arguments = function->arguments();
+ for (AbstractMetaArgument *argument : arguments) {
+ AbstractMetaType* atype = argument->type();
+
+ AbstractMetaArgument *arg = argument->copy();
+ arg->replaceType(inheritTemplateType(templateTypes, atype, &ok));
+ if (!ok)
+ break;
+ f->addArgument(arg);
+ }
+
+ if (!ok) {
+ delete f;
+ continue;
+ }
+
+ // There is no base class in the target language to inherit from here, so
+ // the template instantiation is the class that implements the function.
+ f->setImplementingClass(subclass);
+
+ // We also set it as the declaring class, since the superclass is
+ // supposed to disappear. This allows us to make certain function modifications
+ // on the inherited functions.
+ f->setDeclaringClass(subclass);
+
+
+ if (f->isConstructor() && subclass->isTypeDef()) {
+ f->setName(subclass->name());
+ f->setOriginalName(subclass->name());
+ } else if (f->isConstructor()) {
+ delete f;
+ continue;
+ }
+
+ // if the instantiation has a function named the same as an existing
+ // function we have shadowing so we need to skip it.
+ bool found = false;
+ for (int i = 0; i < funcs.size(); ++i) {
+ if (funcs.at(i)->name() == f->name()) {
+ found = true;
+ continue;
+ }
+ }
+ if (found) {
+ delete f;
+ continue;
+ }
+
+ ComplexTypeEntry* te = subclass->typeEntry();
+ FunctionModificationList mods = function->modifications(templateClass);
+ for (int i = 0; i < mods.size(); ++i) {
+ FunctionModification mod = mods.at(i);
+ mod.signature = f->minimalSignature();
+
+ // If we ever need it... Below is the code to do
+ // substitution of the template instantation type inside
+ // injected code..
+#if 0
+ if (mod.modifiers & Modification::CodeInjection) {
+ for (int j = 0; j < template_types.size(); ++j) {
+ CodeSnip &snip = mod.snips.last();
+ QString code = snip.code();
+ code.replace(QString::fromLatin1("$$QT_TEMPLATE_%1$$").arg(j),
+ template_types.at(j)->typeEntry()->qualifiedCppName());
+ snip.codeList.clear();
+ snip.addCode(code);
+ }
+ }
+#endif
+ te->addFunctionModification(mod);
+ }
+
+ subclass->addFunction(f);
+ }
+
+ subclass->setTemplateBaseClass(templateClass);
+ subclass->setTemplateBaseClassInstantiations(templateTypes);
+ subclass->setInterfaces(templateClass->interfaces());
+ subclass->setBaseClass(templateClass->baseClass());
+
+ return true;
+}
+
+void AbstractMetaBuilderPrivate::parseQ_Property(AbstractMetaClass *metaClass,
+ const QStringList &declarations)
+{
+ for (int i = 0; i < declarations.size(); ++i) {
+ QString p = declarations.at(i);
+
+ QStringList l = p.split(QLatin1String(" "));
+
+
+ QStringList qualifiedScopeName = currentScope()->qualifiedName();
+ bool ok = false;
+ AbstractMetaType* type = 0;
+ QString scope;
+ for (int j = qualifiedScopeName.size(); j >= 0; --j) {
+ scope = j > 0 ? QStringList(qualifiedScopeName.mid(0, j)).join(colonColon()) + colonColon() : QString();
+ TypeInfo info;
+ info.setQualifiedName((scope + l.at(0)).split(colonColon()));
+
+ type = translateType(info, &ok);
+ if (type && ok)
+ break;
+ }
+
+ if (!type || !ok) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Unable to decide type of property: '%1' in class '%2'")
+ .arg(l.at(0), metaClass->name());
+ continue;
+ }
+
+ QString typeName = scope + l.at(0);
+
+ QPropertySpec* spec = new QPropertySpec(type->typeEntry());
+ spec->setName(l.at(1));
+ spec->setIndex(i);
+
+ for (int pos = 2; pos + 1 < l.size(); pos += 2) {
+ if (l.at(pos) == QLatin1String("READ"))
+ spec->setRead(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("WRITE"))
+ spec->setWrite(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("DESIGNABLE"))
+ spec->setDesignable(l.at(pos + 1));
+ else if (l.at(pos) == QLatin1String("RESET"))
+ spec->setReset(l.at(pos + 1));
+ }
+
+ metaClass->addPropertySpec(spec);
+ delete type;
+ }
+}
+
+static AbstractMetaFunction* findCopyCtor(AbstractMetaClass* cls)
+{
+ AbstractMetaFunctionList functions = cls->queryFunctions(AbstractMetaClass::Invisible);
+ functions << cls->queryFunctions(AbstractMetaClass::Visible);
+
+ for (AbstractMetaFunction *f : qAsConst(functions)) {
+ const AbstractMetaFunction::FunctionType t = f->functionType();
+ if (t == AbstractMetaFunction::CopyConstructorFunction || t == AbstractMetaFunction::AssignmentOperatorFunction)
+ return f;
+ }
+ return 0;
+}
+
+void AbstractMetaBuilderPrivate::setupClonable(AbstractMetaClass *cls)
+{
+ bool result = true;
+
+ // find copy ctor for the current class
+ AbstractMetaFunction* copyCtor = findCopyCtor(cls);
+ if (copyCtor) { // if exists a copy ctor in this class
+ result = copyCtor->isPublic();
+ } else { // else... lets find one in the parent class
+ QQueue<AbstractMetaClass*> baseClasses;
+ if (cls->baseClass())
+ baseClasses.enqueue(cls->baseClass());
+ baseClasses << cls->interfaces().toList();
+
+ while (!baseClasses.isEmpty()) {
+ AbstractMetaClass* currentClass = baseClasses.dequeue();
+ baseClasses << currentClass->interfaces().toList();
+ if (currentClass->baseClass())
+ baseClasses.enqueue(currentClass->baseClass());
+
+ copyCtor = findCopyCtor(currentClass);
+ if (copyCtor) {
+ result = copyCtor->isPublic();
+ break;
+ }
+ }
+ }
+ cls->setHasCloneOperator(result);
+}
+
+void AbstractMetaBuilderPrivate::setupExternalConversion(AbstractMetaClass *cls)
+{
+ const AbstractMetaFunctionList &convOps = cls->operatorOverloads(AbstractMetaClass::ConversionOp);
+ for (AbstractMetaFunction *func : convOps) {
+ if (func->isModifiedRemoved())
+ continue;
+ AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, func->type()->typeEntry());
+ if (!metaClass)
+ continue;
+ metaClass->addExternalConversionOperator(func);
+ }
+ const AbstractMetaClassList &innerClasses = cls->innerClasses();
+ for (AbstractMetaClass *innerClass : innerClasses)
+ setupExternalConversion(innerClass);
+}
+
+static void writeRejectLogFile(const QString &name,
+ const QMap<QString, AbstractMetaBuilder::RejectReason> &rejects)
+{
+ QFile f(name);
+ if (!f.open(QIODevice::WriteOnly | QIODevice::Text)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("failed to write log file: '%1'")
+ .arg(QDir::toNativeSeparators(f.fileName()));
+ return;
+ }
+
+ QTextStream s(&f);
+
+
+ for (int reason = 0; reason < AbstractMetaBuilder::NoReason; ++reason) {
+ s << QString(72, QLatin1Char('*')) << endl;
+ switch (reason) {
+ case AbstractMetaBuilder::NotInTypeSystem:
+ s << "Not in type system";
+ break;
+ case AbstractMetaBuilder::GenerationDisabled:
+ s << "Generation disabled by type system";
+ break;
+ case AbstractMetaBuilder::RedefinedToNotClass:
+ s << "Type redefined to not be a class";
+ break;
+
+ case AbstractMetaBuilder::UnmatchedReturnType:
+ s << "Unmatched return type";
+ break;
+
+ case AbstractMetaBuilder::UnmatchedArgumentType:
+ s << "Unmatched argument type";
+ break;
+
+ case AbstractMetaBuilder::ApiIncompatible:
+ s << "Incompatible API";
+ break;
+
+ default:
+ s << "unknown reason";
+ break;
+ }
+
+ s << endl;
+
+ for (QMap<QString, AbstractMetaBuilder::RejectReason>::const_iterator it = rejects.constBegin();
+ it != rejects.constEnd(); ++it) {
+ if (it.value() != reason)
+ continue;
+ s << " - " << it.key() << endl;
+ }
+
+ s << QString(72, QLatin1Char('*')) << endl << endl;
+ }
+
+}
+
+void AbstractMetaBuilderPrivate::dumpLog() const
+{
+ writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_classes.log"), m_rejectedClasses);
+ writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_enums.log"), m_rejectedEnums);
+ writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_functions.log"), m_rejectedFunctions);
+ writeRejectLogFile(m_logDirectory + QLatin1String("mjb_rejected_fields.log"), m_rejectedFields);
+}
+
+AbstractMetaClassList AbstractMetaBuilderPrivate::classesTopologicalSorted(const AbstractMetaClass *cppClass,
+ const Dependencies &additionalDependencies) const
+{
+ QLinkedList<int> unmappedResult;
+ QHash<QString, int> map;
+ QHash<int, AbstractMetaClass*> reverseMap;
+
+ const AbstractMetaClassList& classList = cppClass ? cppClass->innerClasses() : m_metaClasses;
+
+ int i = 0;
+ for (AbstractMetaClass *clazz : classList) {
+ if (map.contains(clazz->qualifiedCppName()))
+ continue;
+ map[clazz->qualifiedCppName()] = i;
+ reverseMap[i] = clazz;
+ i++;
+ }
+
+ Graph graph(map.count());
+
+ for (const Dependency &dep : additionalDependencies) {
+ const int parentIndex = map.value(dep.parent, -1);
+ const int childIndex = map.value(dep.child, -1);
+ if (parentIndex >= 0 && childIndex >= 0) {
+ graph.addEdge(parentIndex, childIndex);
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "AbstractMetaBuilder::classesTopologicalSorted(): Invalid additional dependency: "
+ << dep.child << " -> " << dep.parent << '.';
+ }
+ }
+
+ // TODO choose a better name to these regexs
+ static const QRegularExpression regex1(QStringLiteral("\\(.*\\)"));
+ Q_ASSERT(regex1.isValid());
+ static const QRegularExpression regex2(QStringLiteral("::.*"));
+ Q_ASSERT(regex2.isValid());
+ for (AbstractMetaClass *clazz : classList) {
+ if (clazz->enclosingClass() && map.contains(clazz->enclosingClass()->qualifiedCppName()))
+ graph.addEdge(map[clazz->enclosingClass()->qualifiedCppName()], map[clazz->qualifiedCppName()]);
+
+ const AbstractMetaClassList &bases = getBaseClasses(clazz);
+ for (AbstractMetaClass *baseClass : bases) {
+ // Fix polymorphic expression
+ if (clazz->baseClass() == baseClass)
+ clazz->setBaseClass(baseClass);
+
+ if (map.contains(baseClass->qualifiedCppName()))
+ graph.addEdge(map[baseClass->qualifiedCppName()], map[clazz->qualifiedCppName()]);
+ }
+
+ const AbstractMetaFunctionList &functions = clazz->functions();
+ for (AbstractMetaFunction *func : functions) {
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+ // check methods with default args
+ QString defaultExpression = arg->originalDefaultValueExpression();
+ if (!defaultExpression.isEmpty()) {
+ if (defaultExpression == QLatin1String("0") && arg->type()->isValue())
+ defaultExpression = arg->type()->name();
+
+ defaultExpression.remove(regex1);
+ defaultExpression.remove(regex2);
+ }
+ if (!defaultExpression.isEmpty()) {
+ QString exprClassName = clazz->qualifiedCppName() + colonColon() + defaultExpression;
+ if (!map.contains(exprClassName)) {
+ bool found = false;
+ for (AbstractMetaClass *baseClass : bases) {
+ exprClassName = baseClass->qualifiedCppName() + colonColon() + defaultExpression;
+ if (map.contains(exprClassName)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ if (map.contains(defaultExpression))
+ exprClassName = defaultExpression;
+ else
+ exprClassName.clear();
+ }
+ }
+ if (!exprClassName.isEmpty() && exprClassName != clazz->qualifiedCppName())
+ graph.addEdge(map[exprClassName], map[clazz->qualifiedCppName()]);
+ }
+ }
+ }
+ }
+
+ AbstractMetaClassList result;
+ unmappedResult = graph.topologicalSort();
+ if (unmappedResult.isEmpty() && graph.nodeCount()) {
+ QTemporaryFile tempFile;
+ tempFile.setAutoRemove(false);
+ tempFile.open();
+ QHash<int, QString> hash;
+ QHash<QString, int>::iterator it = map.begin();
+ for (; it != map.end(); ++it)
+ hash[it.value()] = it.key();
+ graph.dumpDot(hash, tempFile.fileName());
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Cyclic dependency found! Graph can be found at "
+ << QDir::toNativeSeparators(tempFile.fileName());
+ } else {
+ for (int i : qAsConst(unmappedResult)) {
+ Q_ASSERT(reverseMap.contains(i));
+ if (!reverseMap[i]->isInterface())
+ result << reverseMap[i];
+ }
+ }
+
+ return result;
+}
+
+AbstractMetaClassList AbstractMetaBuilder::classesTopologicalSorted(const AbstractMetaClass *cppClass,
+ const Dependencies &additionalDependencies) const
+{
+ return d->classesTopologicalSorted(cppClass, additionalDependencies);
+}
+
+AbstractMetaArgumentList AbstractMetaBuilderPrivate::reverseList(const AbstractMetaArgumentList &list)
+{
+ AbstractMetaArgumentList ret;
+
+ int index = list.size();
+ for (AbstractMetaArgument *arg : list) {
+ arg->setArgumentIndex(index);
+ ret.prepend(arg);
+ index--;
+ }
+
+ return ret;
+}
+
+void AbstractMetaBuilder::setGlobalHeader(const QString& globalHeader)
+{
+ d->m_globalHeader = QFileInfo(globalHeader);
+}
+
+void AbstractMetaBuilderPrivate::setInclude(TypeEntry *te, const QString &fileName) const
+{
+ QFileInfo info(fileName);
+ if (m_globalHeader.fileName() != info.fileName())
+ te->setInclude(Include(Include::IncludePath, info.fileName()));
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class Container>
+static void debugFormatSequence(QDebug &d, const char *key, const Container& c,
+ const char *separator = ", ")
+{
+ typedef typename Container::const_iterator ConstIt;
+ if (c.isEmpty())
+ return;
+ const ConstIt begin = c.begin();
+ const ConstIt end = c.end();
+ d << "\n " << key << '[' << c.size() << "]=(";
+ for (ConstIt it = begin; it != end; ++it) {
+ if (it != begin)
+ d << separator;
+ d << *it;
+ }
+ d << ')';
+}
+
+void AbstractMetaBuilder::formatDebug(QDebug &debug) const
+{
+ debug << "m_globalHeader=" << d->m_globalHeader.absoluteFilePath();
+ debugFormatSequence(debug, "qtMetaTypeDeclaredTypeNames", d->m_qmetatypeDeclaredTypenames);
+ debugFormatSequence(debug, "globalEnums", d->m_globalEnums, "\n");
+ debugFormatSequence(debug, "globalFunctions", d->m_globalFunctions, "\n");
+ if (const int scopeCount = d->m_scopes.size()) {
+ debug << "\n scopes[" << scopeCount << "]=(";
+ for (int i = 0; i < scopeCount; ++i) {
+ if (i)
+ debug << ", ";
+ _CodeModelItem::formatKind(debug, d->m_scopes.at(i)->kind());
+ debug << " \"" << d->m_scopes.at(i)->name() << '"';
+ }
+ debug << ')';
+ }
+ debugFormatSequence(debug, "classes", d->m_metaClasses, "\n");
+ debugFormatSequence(debug, "templates", d->m_templates, "\n");
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaBuilder(";
+ ab.formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
new file mode 100644
index 000000000..f7427d488
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ABSTRACTMETABUILDER_H
+#define ABSTRACTMETABUILDER_H
+
+#include "abstractmetalang_typedefs.h"
+#include "dependency.h"
+
+QT_FORWARD_DECLARE_CLASS(QIODevice)
+
+class AbstractMetaBuilderPrivate;
+class AbstractMetaClass;
+class AbstractMetaEnumValue;
+
+class AbstractMetaBuilder
+{
+public:
+ enum RejectReason {
+ NotInTypeSystem,
+ GenerationDisabled,
+ RedefinedToNotClass,
+ UnmatchedArgumentType,
+ UnmatchedReturnType,
+ ApiIncompatible,
+ NoReason
+ };
+
+ AbstractMetaBuilder();
+ virtual ~AbstractMetaBuilder();
+
+ AbstractMetaClassList classes() const;
+ AbstractMetaClassList templates() const;
+ AbstractMetaClassList smartPointers() const;
+ AbstractMetaFunctionList globalFunctions() const;
+ AbstractMetaEnumList globalEnums() const;
+ // QtScript
+ QSet<QString> qtMetaTypeDeclaredTypeNames() const;
+
+ /**
+ * Sorts a list of classes topologically, if an AbstractMetaClass object
+ * is passed the list of classes will be its inner classes, otherwise
+ * the list will be the module global classes.
+ * \return a list of classes sorted topologically
+ */
+ AbstractMetaClassList classesTopologicalSorted(const AbstractMetaClass *cppClass = Q_NULLPTR,
+ const Dependencies &additionalDependencies = Dependencies()) const;
+
+ bool build(const QByteArrayList &arguments, unsigned clangFlags = 0);
+ void setLogDirectory(const QString& logDir);
+
+ /**
+ * AbstractMetaBuilder should know what's the global header being used,
+ * so any class declared under this header wont have the include file
+ * filled.
+ */
+ void setGlobalHeader(const QString& globalHeader);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+protected:
+ virtual AbstractMetaClass *createMetaClass();
+ virtual AbstractMetaEnum *createMetaEnum();
+ virtual AbstractMetaEnumValue *createMetaEnumValue();
+ virtual AbstractMetaField *createMetaField();
+ virtual AbstractMetaFunction *createMetaFunction();
+ virtual AbstractMetaArgument *createMetaArgument();
+ virtual AbstractMetaType *createMetaType();
+
+private:
+ friend class AbstractMetaBuilderPrivate;
+ AbstractMetaBuilderPrivate *d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaBuilder &ab);
+#endif
+
+#endif // ABSTRACTMETBUILDER_H
diff --git a/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
new file mode 100644
index 000000000..96a6fdbfd
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder_p.h
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ABSTRACTMETABUILDER_P_H
+#define ABSTRACTMETABUILDER_P_H
+
+#include "abstractmetabuilder.h"
+#include "parser/codemodel_fwd.h"
+#include "abstractmetalang.h"
+#include "typesystem.h"
+#include "typeparser.h"
+
+#include <QSet>
+#include <QFileInfo>
+
+class TypeDatabase;
+
+class AbstractMetaBuilderPrivate
+{
+public:
+ AbstractMetaBuilderPrivate();
+ ~AbstractMetaBuilderPrivate();
+
+ static FileModelItem buildDom(const QByteArrayList &arguments, unsigned clangFlags);
+ void traverseDom(const FileModelItem &dom);
+
+ void dumpLog() const;
+ AbstractMetaClassList classesTopologicalSorted(const AbstractMetaClass *cppClass = Q_NULLPTR,
+ const Dependencies &additionalDependencies = Dependencies()) const;
+ ScopeModelItem popScope() { return m_scopes.takeLast(); }
+
+ void pushScope(ScopeModelItem item) { m_scopes << item; }
+
+ ScopeModelItem currentScope() const { return m_scopes.last(); }
+
+ AbstractMetaClass *argumentToClass(ArgumentModelItem);
+
+ void figureOutEnumValuesForClass(AbstractMetaClass *metaClass, QSet<AbstractMetaClass *> *classes);
+ int figureOutEnumValue(const QString &name, int value, AbstractMetaEnum *meta_enum, AbstractMetaFunction *metaFunction = 0);
+ void figureOutEnumValues();
+ void figureOutDefaultEnumArguments();
+
+ void addAbstractMetaClass(AbstractMetaClass *cls);
+ AbstractMetaClass *traverseTypeDef(const FileModelItem &dom,
+ const TypeDefModelItem &typeDef);
+ AbstractMetaClass *traverseClass(const FileModelItem &dom,
+ const ClassModelItem &item);
+ AbstractMetaClass *currentTraversedClass(ScopeModelItem item);
+ void traverseScopeMembers(ScopeModelItem item, AbstractMetaClass *metaClass);
+ void traverseClassMembers(ClassModelItem scopeItem);
+ void traverseNamespaceMembers(NamespaceModelItem scopeItem);
+ bool setupInheritance(AbstractMetaClass *metaClass);
+ AbstractMetaClass *traverseNamespace(const FileModelItem &dom,
+ const NamespaceModelItem &item);
+ AbstractMetaEnum *traverseEnum(EnumModelItem item, AbstractMetaClass *enclosing,
+ const QSet<QString> &enumsDeclarations);
+ void traverseEnums(ScopeModelItem item, AbstractMetaClass *parent,
+ const QStringList &enumsDeclarations);
+ AbstractMetaFunctionList classFunctionList(const ScopeModelItem &scopeItem);
+ AbstractMetaFunctionList templateClassFunctionList(const ScopeModelItem &scopeItem,
+ AbstractMetaClass *metaClass);
+ void traverseFunctions(ScopeModelItem item, AbstractMetaClass *parent);
+ void applyFunctionModifications(AbstractMetaFunction* func);
+ 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(FunctionModelItem function);
+ AbstractMetaField *traverseField(VariableModelItem field,
+ const AbstractMetaClass *cls);
+ void checkFunctionModifications();
+ void registerHashFunction(FunctionModelItem functionItem);
+ void registerToStringCapability(FunctionModelItem functionItem);
+
+ /**
+ * A conversion operator function should not have its owner class as
+ * its return type, but unfortunately it does. This function fixes the
+ * return type of operator functions of this kind making the return type
+ * be the same as it is supposed to generate when used in C++.
+ * If the returned type is a wrapped C++ class, this method also adds the
+ * conversion operator to the collection of external conversions of the
+ * said class.
+ * \param metaFunction conversion operator function to be fixed.
+ */
+ void fixReturnTypeOfConversionOperator(AbstractMetaFunction *metaFunction);
+
+ void parseQ_Property(AbstractMetaClass *metaClass, const QStringList &declarations);
+ void setupEquals(AbstractMetaClass *metaClass);
+ void setupComparable(AbstractMetaClass *metaClass);
+ void setupClonable(AbstractMetaClass *cls);
+ void setupExternalConversion(AbstractMetaClass *cls);
+ void setupFunctionDefaults(AbstractMetaFunction *metaFunction,
+ AbstractMetaClass *metaClass);
+
+ QString fixDefaultValue(ArgumentModelItem item, AbstractMetaType *type,
+ AbstractMetaFunction *fnc, AbstractMetaClass *,
+ int argumentIndex);
+ AbstractMetaType* translateType(double vr, const AddedFunction::TypeInfo &typeInfo);
+ AbstractMetaType *translateType(const TypeInfo &type, bool *ok,
+ bool resolveType = true,
+ bool resolveScope = true);
+
+ int findOutValueFromString(const QString &stringValue, bool &ok);
+
+ void decideUsagePattern(AbstractMetaType *type);
+
+ AbstractMetaClass *findTemplateClass(const QString& name, const AbstractMetaClass *context,
+ TypeParser::Info *info = Q_NULLPTR,
+ ComplexTypeEntry **baseContainerType = Q_NULLPTR) const;
+ AbstractMetaClassList getBaseClasses(const AbstractMetaClass *metaClass) const;
+ bool ancestorHasPrivateCopyConstructor(const AbstractMetaClass *metaClass) const;
+
+ bool inheritTemplate(AbstractMetaClass *subclass,
+ const AbstractMetaClass *templateClass,
+ const TypeParser::Info &info);
+ AbstractMetaType *inheritTemplateType(const QVector<AbstractMetaType *> &templateTypes,
+ const AbstractMetaType *metaType,
+ bool *ok = Q_NULLPTR);
+
+ bool isQObject(const FileModelItem &dom, const QString &qualifiedName);
+ bool isEnum(const FileModelItem &dom, const QStringList &qualifiedName);
+
+ void fixQObjectForScope(const FileModelItem &dom, const TypeDatabase *types,
+ const NamespaceModelItem &item);
+
+ void sortLists();
+ AbstractMetaArgumentList reverseList(const AbstractMetaArgumentList &list);
+ void setInclude(TypeEntry *te, const QString &fileName) const;
+ void fixArgumentNames(AbstractMetaFunction *func);
+ void fillAddedFunctions(AbstractMetaClass *metaClass);
+
+ AbstractMetaBuilder *q;
+ AbstractMetaClassList m_metaClasses;
+ AbstractMetaClassList m_templates;
+ AbstractMetaClassList m_smartPointers;
+ AbstractMetaFunctionList m_globalFunctions;
+ AbstractMetaEnumList m_globalEnums;
+
+ QSet<const TypeEntry *> m_usedTypes;
+
+ typedef QMap<QString, AbstractMetaBuilder::RejectReason> RejectMap;
+
+ RejectMap m_rejectedClasses;
+ RejectMap m_rejectedEnums;
+ RejectMap m_rejectedFunctions;
+ RejectMap m_rejectedFields;
+
+ QList<AbstractMetaEnum *> m_enums;
+
+ QList<QPair<AbstractMetaArgument *, AbstractMetaFunction *> > m_enumDefaultArguments;
+
+ QHash<QString, AbstractMetaEnumValue *> m_enumValues;
+
+ AbstractMetaClass *m_currentClass;
+ QList<ScopeModelItem> m_scopes;
+ QString m_namespacePrefix;
+
+ QSet<AbstractMetaClass *> m_setupInheritanceDone;
+
+ // QtScript
+ QSet<QString> m_qmetatypeDeclaredTypenames;
+
+ QString m_logDirectory;
+ QFileInfo m_globalHeader;
+};
+
+#endif // ABSTRACTMETBUILDER_P_H
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.cpp b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
new file mode 100644
index 000000000..4fa009fd2
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp
@@ -0,0 +1,2784 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "abstractmetalang.h"
+#include "reporthandler.h"
+#include "typedatabase.h"
+#include "typesystem.h"
+
+#ifndef QT_NO_DEBUG_STREAM
+# include <QtCore/QMetaEnum>
+# include <QtCore/QMetaObject>
+#endif
+
+#include <QtCore/QRegularExpression>
+#include <QtCore/QStack>
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaAttributes *aa)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaAttributes(";
+ if (aa)
+ d << aa->attributes();
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+/*******************************************************************************
+ * AbstractMetaVariable
+ */
+
+AbstractMetaVariable::AbstractMetaVariable(const AbstractMetaVariable &other)
+{
+ m_originalName = other.m_originalName;
+ m_name = other.m_name;
+ m_type = other.m_type->copy();
+ m_hasName = other.m_hasName;
+ m_doc = other.m_doc;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaVariable *av)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaVariable(";
+ if (av) {
+ d << av->type()->name() << ' ' << av->name();
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+/*******************************************************************************
+ * AbstractMetaType
+ */
+
+AbstractMetaType::AbstractMetaType()
+ :m_typeEntry(0),
+ m_arrayElementCount(0),
+ m_arrayElementType(0),
+ m_originalTemplateType(0),
+ m_pattern(InvalidPattern),
+ m_constant(false),
+ m_cppInstantiation(true),
+ m_indirections(0),
+ m_reserved(0),
+ m_referenceType(NoReference)
+{
+}
+
+AbstractMetaType::~AbstractMetaType()
+{
+ qDeleteAll(m_children);
+ m_instantiations.clear();
+}
+
+QString AbstractMetaType::package() const
+{
+ return m_typeEntry->targetLangPackage();
+}
+
+QString AbstractMetaType::name() const
+{
+ if (m_name.isNull())
+ // avoid constLast to stay Qt 5.5 compatible
+ m_name = m_typeEntry->targetLangName().split(QLatin1String("::")).last();
+ return m_name;
+}
+
+QString AbstractMetaType::fullName() const
+{
+ return m_typeEntry->qualifiedTargetLangName();
+}
+
+AbstractMetaType *AbstractMetaType::copy() const
+{
+ AbstractMetaType *cpy = new AbstractMetaType;
+
+ cpy->setTypeUsagePattern(typeUsagePattern());
+ cpy->setConstant(isConstant());
+ cpy->setReferenceType(referenceType());
+ cpy->setIndirections(indirections());
+ cpy->setInstantiations(instantiations());
+ cpy->setArrayElementCount(arrayElementCount());
+ cpy->setOriginalTypeDescription(originalTypeDescription());
+ cpy->setOriginalTemplateType(originalTemplateType() ? originalTemplateType()->copy() : 0);
+
+ cpy->setArrayElementType(arrayElementType() ? arrayElementType()->copy() : 0);
+
+ cpy->setTypeEntry(typeEntry());
+
+ return cpy;
+}
+
+QString AbstractMetaType::cppSignature() const
+{
+ if (m_cachedCppSignature.isEmpty()) {
+ if (isConstant())
+ m_cachedCppSignature += QLatin1String("const ");
+
+ m_cachedCppSignature += typeEntry()->qualifiedCppName();
+
+ if (hasInstantiationInCpp()) {
+ AbstractMetaTypeList types = instantiations();
+ m_cachedCppSignature += QLatin1Char('<');
+ for (int i = 0; i < types.count(); ++i) {
+ if (i > 0)
+ m_cachedCppSignature += QLatin1String(", ");
+ m_cachedCppSignature += types[i]->cppSignature();
+ }
+ m_cachedCppSignature += QLatin1String(" >");
+ }
+
+ if (indirections() || m_referenceType != NoReference) {
+ m_cachedCppSignature += QLatin1Char(' ');
+ if (indirections())
+ m_cachedCppSignature += QString(indirections(), QLatin1Char('*'));
+ switch (referenceType()) {
+ case NoReference:
+ break;
+ case LValueReference:
+ m_cachedCppSignature += QLatin1Char('&');
+ break;
+ case RValueReference:
+ m_cachedCppSignature += QLatin1String("&&");
+ break;
+ }
+ }
+ }
+ return m_cachedCppSignature;
+}
+
+AbstractMetaType::TypeUsagePattern AbstractMetaType::determineUsagePattern() const
+{
+ if (m_typeEntry->isTemplateArgument() || m_referenceType == RValueReference)
+ return InvalidPattern;
+
+ if (m_typeEntry->isPrimitive() && (!actualIndirections()
+ || (isConstant() && m_referenceType == LValueReference && !indirections()))) {
+ return PrimitivePattern;
+ }
+
+ if (m_typeEntry->isVoid())
+ return NativePointerPattern;
+
+ if (m_typeEntry->isVarargs())
+ return VarargsPattern;
+
+ if (m_typeEntry->isString() && indirections() == 0
+ && (isConstant() == (m_referenceType == LValueReference)
+ || isConstant())) {
+ return StringPattern;
+ }
+
+ if (m_typeEntry->isChar()
+ && indirections() == 0
+ && isConstant() == (m_referenceType == LValueReference)) {
+ return CharPattern;
+ }
+
+ if (m_typeEntry->isJObjectWrapper()
+ && indirections() == 0
+ && isConstant() == (m_referenceType == LValueReference)) {
+ return JObjectWrapperPattern;
+ }
+
+ if (m_typeEntry->isVariant()
+ && indirections() == 0
+ && isConstant() == (m_referenceType == LValueReference)) {
+ return VariantPattern;
+ }
+
+ if (m_typeEntry->isEnum() && actualIndirections() == 0)
+ return EnumPattern;
+
+ if (m_typeEntry->isObject()) {
+ if (indirections() == 0 && m_referenceType == NoReference)
+ return ValuePattern;
+ return static_cast<const ComplexTypeEntry *>(m_typeEntry)->isQObject()
+ ? QObjectPattern : ObjectPattern;
+ }
+
+ if (m_typeEntry->isContainer() && indirections() == 0)
+ return ContainerPattern;
+
+ if (m_typeEntry->isSmartPointer() && indirections() == 0)
+ return SmartPointerPattern;
+
+ if (m_typeEntry->isFlags() && indirections() == 0
+ && (isConstant() == (m_referenceType == LValueReference)))
+ return FlagsPattern;
+
+ if (m_typeEntry->isArray())
+ return ArrayPattern;
+
+ if (m_typeEntry->isThread()) {
+ Q_ASSERT(indirections() == 1);
+ return ThreadPattern;
+ }
+
+ if (m_typeEntry->isValue())
+ return indirections() == 1 ? ValuePointerPattern : ValuePattern;
+
+ if (ReportHandler::isDebug(ReportHandler::FullDebug)) {
+ qCDebug(lcShiboken)
+ << QStringLiteral("native pointer pattern for '%1'").arg(cppSignature());
+ }
+ return NativePointerPattern;
+}
+
+void AbstractMetaType::decideUsagePattern()
+{
+ TypeUsagePattern pattern = determineUsagePattern();
+ if (m_typeEntry->isObject() && indirections() == 1
+ && m_referenceType == LValueReference && isConstant()) {
+ // const-references to pointers can be passed as pointers
+ setReferenceType(NoReference);
+ setConstant(false);
+ pattern = static_cast<const ComplexTypeEntry *>(m_typeEntry)->isQObject()
+ ? QObjectPattern : ObjectPattern;
+ }
+ setTypeUsagePattern(pattern);
+}
+
+bool AbstractMetaType::hasTemplateChildren() const
+{
+ QStack<AbstractMetaType *> children;
+ children << m_children;
+
+ // Recursively iterate over the children / descendants of the type, to check if any of them
+ // corresponds to a template argument type.
+ while (!children.isEmpty()) {
+ AbstractMetaType *child = children.pop();
+ if (child->typeEntry()->isTemplateArgument())
+ return true;
+ children << child->m_children;
+ }
+
+ return false;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaType *at)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaType(";
+ if (at)
+ d << at->name();
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+/*******************************************************************************
+ * AbstractMetaArgument
+ */
+AbstractMetaArgument *AbstractMetaArgument::copy() const
+{
+ return new AbstractMetaArgument(*this);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaArgument *aa)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaArgument(";
+ if (aa)
+ d << aa->toString();
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+/*******************************************************************************
+ * AbstractMetaFunction
+ */
+AbstractMetaFunction::~AbstractMetaFunction()
+{
+ qDeleteAll(m_arguments);
+ delete m_type;
+}
+
+/*******************************************************************************
+ * Indicates that this function has a modification that removes it
+ */
+bool AbstractMetaFunction::isModifiedRemoved(int types) const
+{
+ const FunctionModificationList &mods = modifications(implementingClass());
+ for (const FunctionModification &mod : mods) {
+ if (!mod.isRemoveModifier())
+ continue;
+
+ if ((mod.removal & types) == types)
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::needsCallThrough() const
+{
+ if (ownerClass()->isInterface())
+ return false;
+ if (referenceCounts(implementingClass()).size() > 0)
+ return true;
+ if (argumentsHaveNativeId() || !isStatic())
+ return true;
+
+ for (const AbstractMetaArgument *arg : m_arguments) {
+ if (arg->type()->isArray() || arg->type()->isTargetLangEnum() || arg->type()->isTargetLangFlags())
+ return true;
+ }
+
+ if (type() && (type()->isArray() || type()->isTargetLangEnum() || type()->isTargetLangFlags()))
+ return true;
+
+ for (int i = -1; i <= arguments().size(); ++i) {
+ TypeSystem::Ownership owner = this->ownership(implementingClass(), TypeSystem::TargetLangCode, i);
+ if (owner != TypeSystem::InvalidOwnership)
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::needsSuppressUncheckedWarning() const
+{
+ for (int i = -1; i <= arguments().size(); ++i) {
+ const QVector<ReferenceCount> &referenceCounts = this->referenceCounts(implementingClass(), i);
+ for (const ReferenceCount &referenceCount : referenceCounts) {
+ if (referenceCount.action != ReferenceCount::Set)
+ return true;
+ }
+ }
+ return false;
+}
+
+QString AbstractMetaFunction::marshalledName() const
+{
+ QString returned = QLatin1String("__qt_") + name();
+ for (const AbstractMetaArgument *arg : m_arguments) {
+ returned += QLatin1Char('_');
+ if (arg->type()->isNativePointer()) {
+ returned += QLatin1String("nativepointer");
+ } else if (arg->type()->isIntegerEnum() || arg->type()->isIntegerFlags()) {
+ returned += QLatin1String("int");
+ } else {
+ QString a = arg->type()->name();
+ a.replace(QLatin1String("[]"), QLatin1String("_3"));
+ a.replace(QLatin1Char('.'), QLatin1Char('_'));
+ returned += a;
+ }
+ }
+ return returned;
+}
+
+bool AbstractMetaFunction::operator<(const AbstractMetaFunction &other) const
+{
+ return compareTo(&other) & NameLessThan;
+}
+
+
+/*!
+ Returns a mask of CompareResult describing how this function is
+ compares to another function
+*/
+AbstractMetaFunction::CompareResult AbstractMetaFunction::compareTo(const AbstractMetaFunction *other) const
+{
+ CompareResult result = 0;
+
+ // Enclosing class...
+ if (ownerClass() == other->ownerClass())
+ result |= EqualImplementor;
+
+ // Attributes
+ if (attributes() == other->attributes())
+ result |= EqualAttributes;
+
+ // Compare types
+ AbstractMetaType *t = type();
+ AbstractMetaType *ot = other->type();
+ if ((!t && !ot) || ((t && ot && t->name() == ot->name())))
+ result |= EqualReturnType;
+
+ // Compare names
+ int cmp = originalName().compare(other->originalName());
+
+ if (cmp < 0)
+ result |= NameLessThan;
+ else if (!cmp)
+ result |= EqualName;
+
+ // compare name after modification...
+ cmp = modifiedName().compare(other->modifiedName());
+ if (!cmp)
+ result |= EqualModifiedName;
+
+ // Compare arguments...
+ AbstractMetaArgumentList minArguments;
+ AbstractMetaArgumentList maxArguments;
+ if (arguments().size() < other->arguments().size()) {
+ minArguments = arguments();
+ maxArguments = other->arguments();
+ } else {
+ minArguments = other->arguments();
+ maxArguments = arguments();
+ }
+
+ int minCount = minArguments.size();
+ int maxCount = maxArguments.size();
+ bool same = true;
+ for (int i = 0; i < maxCount; ++i) {
+ if (i < minCount) {
+ const AbstractMetaArgument *min_arg = minArguments.at(i);
+ const AbstractMetaArgument *max_arg = maxArguments.at(i);
+ if (min_arg->type()->name() != max_arg->type()->name()
+ && (min_arg->defaultValueExpression().isEmpty() || max_arg->defaultValueExpression().isEmpty())) {
+ same = false;
+ break;
+ }
+ } else {
+ if (maxArguments.at(i)->defaultValueExpression().isEmpty()) {
+ same = false;
+ break;
+ }
+ }
+ }
+
+ if (same)
+ result |= minCount == maxCount ? EqualArguments : EqualDefaultValueOverload;
+
+ return result;
+}
+
+AbstractMetaFunction *AbstractMetaFunction::copy() const
+{
+ AbstractMetaFunction *cpy = new AbstractMetaFunction;
+ cpy->setName(name());
+ cpy->setOriginalName(originalName());
+ cpy->setOwnerClass(ownerClass());
+ cpy->setImplementingClass(implementingClass());
+ cpy->setFunctionType(functionType());
+ cpy->setAttributes(attributes());
+ cpy->setDeclaringClass(declaringClass());
+ if (type())
+ cpy->setType(type()->copy());
+ cpy->setConstant(isConstant());
+ cpy->setOriginalAttributes(originalAttributes());
+
+ for (AbstractMetaArgument *arg : m_arguments)
+ cpy->addArgument(arg->copy());
+
+ Q_ASSERT((!type() && !cpy->type())
+ || (type()->instantiations() == cpy->type()->instantiations()));
+
+ return cpy;
+}
+
+bool AbstractMetaFunction::usesRValueReferences() const
+{
+ if (m_functionType == MoveConstructorFunction || m_functionType == MoveAssignmentOperatorFunction)
+ return true;
+ if (m_type && m_type->referenceType() == RValueReference)
+ return true;
+ for (const AbstractMetaArgument *a : m_arguments) {
+ if (a->type()->referenceType() == RValueReference)
+ return true;
+ }
+ return false;
+}
+
+QStringList AbstractMetaFunction::introspectionCompatibleSignatures(const QStringList &resolvedArguments) const
+{
+ AbstractMetaArgumentList arguments = this->arguments();
+ if (arguments.size() == resolvedArguments.size()) {
+ QString signature = name() + QLatin1Char('(') + resolvedArguments.join(QLatin1Char(',')) + QLatin1Char(')');
+ return QStringList(TypeDatabase::normalizedSignature(signature));
+ } else {
+ QStringList returned;
+
+ AbstractMetaArgument *argument = arguments.at(resolvedArguments.size());
+ QStringList minimalTypeSignature = argument->type()->minimalSignature().split(QLatin1String("::"));
+ for (int i = 0; i < minimalTypeSignature.size(); ++i) {
+ returned += introspectionCompatibleSignatures(QStringList(resolvedArguments)
+ << QStringList(minimalTypeSignature.mid(minimalTypeSignature.size() - i - 1)).join(QLatin1String("::")));
+ }
+
+ return returned;
+ }
+}
+
+QString AbstractMetaFunction::signature() const
+{
+ if (m_cachedSignature.isEmpty()) {
+ m_cachedSignature = m_originalName;
+
+ m_cachedSignature += QLatin1Char('(');
+
+ for (int i = 0; i < m_arguments.count(); ++i) {
+ AbstractMetaArgument *a = m_arguments.at(i);
+ AbstractMetaType *t = a->type();
+ if (t) {
+ if (i > 0)
+ m_cachedSignature += QLatin1String(", ");
+ m_cachedSignature += t->cppSignature();
+ // We need to have the argument names in the qdoc files
+ m_cachedSignature += QLatin1Char(' ');
+ m_cachedSignature += a->name();
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("No abstract meta type found for argument '%1' while"
+ "constructing signature for function '%2'.")
+ .arg(a->name(), name());
+ }
+ }
+ m_cachedSignature += QLatin1Char(')');
+
+ if (isConstant())
+ m_cachedSignature += QLatin1String(" const");
+ }
+ return m_cachedSignature;
+}
+
+int AbstractMetaFunction::actualMinimumArgumentCount() const
+{
+ AbstractMetaArgumentList arguments = this->arguments();
+
+ int count = 0;
+ for (int i = 0; i < arguments.size(); ++i && ++count) {
+ if (argumentRemoved(i + 1))
+ --count;
+ else if (!arguments.at(i)->defaultValueExpression().isEmpty())
+ break;
+ }
+
+ return count;
+}
+
+// Returns reference counts for argument at idx, or all arguments if idx == -2
+QVector<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const
+{
+ QVector<ReferenceCount> returned;
+
+ const FunctionModificationList &mods = this->modifications(cls);
+ for (const FunctionModification &mod : mods) {
+ for (const ArgumentModification &argumentMod : mod.argument_mods) {
+ if (argumentMod.index != idx && idx != -2)
+ continue;
+ returned += argumentMod.referenceCounts;
+ }
+ }
+
+ return returned;
+}
+
+
+ArgumentOwner AbstractMetaFunction::argumentOwner(const AbstractMetaClass *cls, int idx) const
+{
+ const FunctionModificationList &mods = this->modifications(cls);
+ for (const FunctionModification &mod : mods) {
+ for (const ArgumentModification &argumentMod : mod.argument_mods) {
+ if (argumentMod.index != idx)
+ continue;
+ return argumentMod.owner;
+ }
+ }
+ return ArgumentOwner();
+}
+
+
+QString AbstractMetaFunction::replacedDefaultExpression(const AbstractMetaClass *cls, int key) const
+{
+ const FunctionModificationList &modifications = this->modifications(cls);
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == key
+ && !argumentModification.replacedDefaultExpression.isEmpty()) {
+ return argumentModification.replacedDefaultExpression;
+ }
+ }
+ }
+
+ return QString();
+}
+
+bool AbstractMetaFunction::removedDefaultExpression(const AbstractMetaClass *cls, int key) const
+{
+ const FunctionModificationList &modifications = this->modifications(cls);
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == key
+ && argumentModification.removedDefaultExpression) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::resetObjectAfterUse(int argumentIdx) const
+{
+ const AbstractMetaClass *cls = declaringClass();
+ const FunctionModificationList &modifications = this->modifications(cls);
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == argumentIdx && argumentModification.resetAfterUse)
+ return true;
+ }
+ }
+
+ return false;
+}
+
+QString AbstractMetaFunction::nullPointerDefaultValue(const AbstractMetaClass *mainClass, int argumentIdx) const
+{
+ Q_ASSERT(nullPointersDisabled(mainClass, argumentIdx));
+
+ const AbstractMetaClass *cls = mainClass;
+ if (!cls)
+ cls = implementingClass();
+
+ do {
+ const FunctionModificationList &modifications = this->modifications(cls);
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == argumentIdx
+ && argumentModification.noNullPointers) {
+ return argumentModification.nullPointerDefaultValue;
+ }
+ }
+ }
+ cls = cls->baseClass();
+ } while (cls && !mainClass); // Once when mainClass, or once for all base classes of implementing class
+
+ return QString();
+
+}
+
+bool AbstractMetaFunction::nullPointersDisabled(const AbstractMetaClass *mainClass, int argumentIdx) const
+{
+ const AbstractMetaClass *cls = mainClass;
+ if (!cls)
+ cls = implementingClass();
+
+ do {
+ const FunctionModificationList &modifications = this->modifications(cls);
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == argumentIdx
+ && argumentModification.noNullPointers) {
+ return true;
+ }
+ }
+ }
+
+ cls = cls->baseClass();
+ } while (cls && !mainClass); // Once when mainClass, or once for all base classes of implementing class
+
+ return false;
+}
+
+QString AbstractMetaFunction::conversionRule(TypeSystem::Language language, int key) const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index != key)
+ continue;
+
+ for (const CodeSnip &snip : argumentModification.conversion_rules) {
+ if (snip.language == language && !snip.code().isEmpty())
+ return snip.code();
+ }
+ }
+ }
+
+ return QString();
+}
+
+QString AbstractMetaFunction::argumentReplaced(int key) const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == key && !argumentModification.replace_value.isEmpty())
+ return argumentModification.replace_value;
+ }
+ }
+
+ return QString();
+}
+
+// FIXME If we remove a arg. in the method at the base class, it will not reflect here.
+bool AbstractMetaFunction::argumentRemoved(int key) const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == key) {
+ if (argumentModification.removed)
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::isVirtualSlot() const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ if (modification.isVirtualSlot())
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::disabledGarbageCollection(const AbstractMetaClass *cls, int key) const
+{
+ typedef QHash<TypeSystem::Language, TypeSystem::Ownership>::const_iterator OwnershipMapIt;
+
+ const FunctionModificationList &modifications = this->modifications(cls);
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index != key)
+ continue;
+
+ for (OwnershipMapIt it = argumentModification.ownerships.cbegin(), end = argumentModification.ownerships.cend(); it != end; ++it) {
+ if (it.value() == TypeSystem::CppOwnership)
+ return true;
+ }
+
+ }
+ }
+
+ return false;
+}
+
+bool AbstractMetaFunction::isDeprecated() const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ if (modification.isDeprecated())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::isThread() const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ if (modification.isThread())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::allowThread() const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ if (modification.allowThread())
+ return true;
+ }
+ return false;
+}
+
+
+TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const
+{
+ const FunctionModificationList &modifications = this->modifications(cls);
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == key)
+ return argumentModification.ownerships.value(language, TypeSystem::InvalidOwnership);
+ }
+ }
+
+ return TypeSystem::InvalidOwnership;
+}
+
+bool AbstractMetaFunction::isRemovedFromAllLanguages(const AbstractMetaClass *cls) const
+{
+ return isRemovedFrom(cls, TypeSystem::All);
+}
+
+bool AbstractMetaFunction::isRemovedFrom(const AbstractMetaClass *cls, TypeSystem::Language language) const
+{
+ const FunctionModificationList &modifications = this->modifications(cls);
+ for (const FunctionModification &modification : modifications) {
+ if ((modification.removal & language) == language)
+ return true;
+ }
+
+ return false;
+
+}
+
+QString AbstractMetaFunction::typeReplaced(int key) const
+{
+ const FunctionModificationList &modifications = this->modifications(declaringClass());
+ for (const FunctionModification &modification : modifications) {
+ for (const ArgumentModification &argumentModification : modification.argument_mods) {
+ if (argumentModification.index == key
+ && !argumentModification.modified_type.isEmpty()) {
+ return argumentModification.modified_type;
+ }
+ }
+ }
+
+ return QString();
+}
+
+QString AbstractMetaFunction::minimalSignature() const
+{
+ if (!m_cachedMinimalSignature.isEmpty())
+ return m_cachedMinimalSignature;
+
+ QString minimalSignature = originalName() + QLatin1Char('(');
+ AbstractMetaArgumentList arguments = this->arguments();
+
+ for (int i = 0; i < arguments.count(); ++i) {
+ AbstractMetaType *t = arguments.at(i)->type();
+ if (t) {
+ if (i > 0)
+ minimalSignature += QLatin1Char(',');
+ minimalSignature += t->minimalSignature();
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QString::fromLatin1("No abstract meta type found for argument '%1' while constructing"
+ " minimal signature for function '%2'.")
+ .arg(arguments.at(i)->name(), name());
+ }
+ }
+ minimalSignature += QLatin1Char(')');
+ if (isConstant())
+ minimalSignature += QLatin1String("const");
+
+ minimalSignature = TypeDatabase::normalizedSignature(minimalSignature);
+ m_cachedMinimalSignature = minimalSignature;
+
+ return minimalSignature;
+}
+
+FunctionModificationList AbstractMetaFunction::modifications(const AbstractMetaClass* implementor) const
+{
+ if (!implementor)
+ implementor = ownerClass();
+
+ if (!implementor)
+ return TypeDatabase::instance()->functionModifications(minimalSignature());
+
+ FunctionModificationList mods;
+ while (implementor) {
+ mods += implementor->typeEntry()->functionModifications(minimalSignature());
+ if ((implementor == implementor->baseClass()) ||
+ (implementor == implementingClass() && (mods.size() > 0)))
+ break;
+ const AbstractMetaClassList &interfaces = implementor->interfaces();
+ for (const AbstractMetaClass *interface : interfaces)
+ mods += this->modifications(interface);
+ implementor = implementor->baseClass();
+ }
+ return mods;
+}
+
+bool AbstractMetaFunction::hasModifications(const AbstractMetaClass *implementor) const
+{
+ return !modifications(implementor).isEmpty();
+}
+
+QString AbstractMetaFunction::argumentName(int index,
+ bool /* create */,
+ const AbstractMetaClass * /* implementor */) const
+{
+ return m_arguments[--index]->name();
+}
+
+bool AbstractMetaFunction::isCallOperator() const
+{
+ return m_name == QLatin1String("operator()");
+}
+
+bool AbstractMetaFunction::hasInjectedCode() const
+{
+ const FunctionModificationList &mods = modifications(ownerClass());
+ for (const FunctionModification &mod : mods) {
+ if (mod.isCodeInjection())
+ return true;
+ }
+ return false;
+}
+
+CodeSnipList AbstractMetaFunction::injectedCodeSnips(TypeSystem::CodeSnipPosition position, TypeSystem::Language language) const
+{
+ CodeSnipList result;
+ const FunctionModificationList &mods = modifications(ownerClass());
+ for (const FunctionModification &mod : mods) {
+ if (mod.isCodeInjection()) {
+ for (const CodeSnip &snip : mod.snips) {
+ if ((snip.language & language) && (snip.position == position || position == TypeSystem::CodeSnipPositionAny))
+ result << snip;
+ }
+ }
+ }
+ return result;
+}
+
+bool AbstractMetaFunction::hasSignatureModifications() const
+{
+ const FunctionModificationList &mods = modifications();
+ for (const FunctionModification &mod : mods) {
+ if (mod.isRenameModifier())
+ return true;
+ for (const ArgumentModification &argmod : mod.argument_mods) {
+ // since zero represents the return type and we're
+ // interested only in checking the function arguments,
+ // it will be ignored.
+ if (argmod.index > 0)
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AbstractMetaFunction::isConversionOperator(QString funcName)
+{
+ static const QRegularExpression opRegEx(QStringLiteral("^operator(?:\\s+(?:const|volatile))?\\s+(\\w+\\s*)&?$"));
+ Q_ASSERT(opRegEx.isValid());
+ return opRegEx.match(funcName).hasMatch();
+}
+
+bool AbstractMetaFunction::isOperatorOverload(QString funcName)
+{
+ if (isConversionOperator(funcName))
+ return true;
+
+ static const QRegularExpression opRegEx(QLatin1String("^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?"
+ "|\\+\\+|\\-\\-|&&|\\|\\||<<[=]?|>>[=]?|~"
+ "|\\[\\]|\\s+delete\\[?\\]?"
+ "|\\(\\)"
+ "|\\s+new\\[?\\]?)$"));
+ Q_ASSERT(opRegEx.isValid());
+ return opRegEx.match(funcName).hasMatch();
+}
+
+bool AbstractMetaFunction::isCastOperator() const
+{
+ return originalName().startsWith(QLatin1String("operator "));
+}
+
+bool AbstractMetaFunction::isArithmeticOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+
+ // It's a dereference operator!
+ if (name == QLatin1String("operator*") && m_arguments.isEmpty())
+ return false;
+
+ return name == QLatin1String("operator+") || name == QLatin1String("operator+=")
+ || name == QLatin1String("operator-") || name == QLatin1String("operator-=")
+ || name == QLatin1String("operator*") || name == QLatin1String("operator*=")
+ || name == QLatin1String("operator/") || name == QLatin1String("operator/=")
+ || name == QLatin1String("operator%") || name == QLatin1String("operator%=")
+ || name == QLatin1String("operator++") || name == QLatin1String("operator--");
+}
+
+bool AbstractMetaFunction::isBitwiseOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == QLatin1String("operator<<") || name == QLatin1String("operator<<=")
+ || name == QLatin1String("operator>>") || name == QLatin1String("operator>>=")
+ || name == QLatin1String("operator&") || name == QLatin1String("operator&=")
+ || name == QLatin1String("operator|") || name == QLatin1String("operator|=")
+ || name == QLatin1String("operator^") || name == QLatin1String("operator^=")
+ || name == QLatin1String("operator~");
+}
+
+bool AbstractMetaFunction::isComparisonOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == QLatin1String("operator<") || name == QLatin1String("operator<=")
+ || name == QLatin1String("operator>") || name == QLatin1String("operator>=")
+ || name == QLatin1String("operator==") || name == QLatin1String("operator!=");
+}
+
+bool AbstractMetaFunction::isLogicalOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == QLatin1String("operator!")
+ || name == QLatin1String("operator&&")
+ || name == QLatin1String("operator||");
+}
+
+bool AbstractMetaFunction::isSubscriptOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ return originalName() == QLatin1String("operator[]");
+}
+
+bool AbstractMetaFunction::isAssignmentOperator() const
+{
+ return m_functionType == AssignmentOperatorFunction
+ || m_functionType == MoveAssignmentOperatorFunction;
+}
+
+bool AbstractMetaFunction::isOtherOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ return !isArithmeticOperator()
+ && !isBitwiseOperator()
+ && !isComparisonOperator()
+ && !isLogicalOperator()
+ && !isConversionOperator()
+ && !isSubscriptOperator()
+ && !isAssignmentOperator();
+}
+
+int AbstractMetaFunction::arityOfOperator() const
+{
+ if (!isOperatorOverload() || isCallOperator())
+ return -1;
+
+ int arity = m_arguments.size();
+
+ // Operator overloads that are class members
+ // implicitly includes the instance and have
+ // one parameter less than their arity,
+ // so we increment it.
+ if (ownerClass() && arity < 2)
+ arity++;
+
+ return arity;
+}
+
+bool AbstractMetaFunction::isInplaceOperator() const
+{
+ if (!isOperatorOverload())
+ return false;
+
+ QString name = originalName();
+ return name == QLatin1String("operator+=") || name == QLatin1String("operator&=")
+ || name == QLatin1String("operator-=") || name == QLatin1String("operator|=")
+ || name == QLatin1String("operator*=") || name == QLatin1String("operator^=")
+ || name == QLatin1String("operator/=") || name == QLatin1String("operator<<=")
+ || name == QLatin1String("operator%=") || name == QLatin1String("operator>>=");
+}
+
+bool AbstractMetaFunction::isVirtual() const
+{
+ return !isFinal() && !isSignal() && !isStatic() && !isFinalInCpp() && !isConstructor();
+}
+
+QString AbstractMetaFunction::modifiedName() const
+{
+ if (m_cachedModifiedName.isEmpty()) {
+ const FunctionModificationList &mods = modifications(implementingClass());
+ for (const FunctionModification &mod : mods) {
+ if (mod.isRenameModifier()) {
+ m_cachedModifiedName = mod.renamedToName;
+ break;
+ }
+ }
+ if (m_cachedModifiedName.isEmpty())
+ m_cachedModifiedName = name();
+ }
+ return m_cachedModifiedName;
+}
+
+QString AbstractMetaFunction::targetLangSignature(bool minimal) const
+{
+ QString s;
+
+ // Attributes...
+ if (!minimal) {
+ // Return type
+ if (type())
+ s += type()->name() + QLatin1Char(' ');
+ else
+ s += QLatin1String("void ");
+ }
+
+ s += modifiedName();
+ s += QLatin1Char('(');
+
+ int j = 0;
+ for (int i = 0; i < m_arguments.size(); ++i) {
+ if (argumentRemoved(i + 1))
+ continue;
+ if (j) {
+ s += QLatin1Char(',');
+ if (!minimal)
+ s += QLatin1Char(' ');
+ }
+ s += m_arguments.at(i)->type()->name();
+
+ if (!minimal) {
+ s += QLatin1Char(' ');
+ s += m_arguments.at(i)->name();
+ }
+ ++j;
+ }
+
+ s += QLatin1Char(')');
+
+ return s;
+}
+
+
+bool function_sorter(AbstractMetaFunction *a, AbstractMetaFunction *b)
+{
+ return a->signature() < b->signature();
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+static inline void formatMetaFunctionBrief(QDebug &d, const AbstractMetaFunction *af)
+{
+ d << '"' << af->minimalSignature() << '"';
+}
+
+void AbstractMetaFunction::formatDebugVerbose(QDebug &d) const
+{
+ d << m_functionType << ' ' << m_type << ' ' << m_name << '(';
+ for (int i = 0, count = m_arguments.size(); i < count; ++i) {
+ if (i)
+ d << ", ";
+ d << m_arguments.at(i);
+ }
+ d << "), signature=\"" << minimalSignature() << '"';
+ if (m_constant)
+ d << " [const]";
+ if (m_invalid)
+ d << " [invalid]";
+ if (m_reverse)
+ d << " [reverse]";
+ if (m_userAdded)
+ d << " [userAdded]";
+ if (m_explicit)
+ d << " [explicit]";
+ if (m_pointerOperator)
+ d << " [operator->]";
+ if (m_isCallOperator)
+ d << " [operator()]";
+ if (m_class)
+ d << " class: " << m_class->name();
+ if (m_implementingClass)
+ d << " implementing class: " << m_implementingClass->name();
+ if (m_declaringClass)
+ d << " declaring class: " << m_declaringClass->name();
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaFunction *af)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaFunction(";
+ if (af) {
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
+ if (d.verbosity() > 2) {
+ af->formatDebugVerbose(d);
+ } else {
+#endif
+ d << "signature=";
+ formatMetaFunctionBrief(d, af);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
+ }
+#endif
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+/*******************************************************************************
+ * AbstractMetaClass
+ */
+AbstractMetaClass::~AbstractMetaClass()
+{
+ qDeleteAll(m_functions);
+ qDeleteAll(m_fields);
+ qDeleteAll(m_enums);
+ if (hasTemplateBaseClassInstantiations())
+ qDeleteAll(templateBaseClassInstantiations());
+}
+
+/*******************************************************************************
+ * Returns true if this class is a subclass of the given class
+ */
+bool AbstractMetaClass::inheritsFrom(const AbstractMetaClass *cls) const
+{
+ Q_ASSERT(cls);
+
+ const AbstractMetaClass *clazz = this;
+ while (clazz) {
+ if (clazz == cls)
+ return true;
+
+ clazz = clazz->baseClass();
+ }
+
+ return false;
+}
+
+/*******************************************************************************
+ * Constructs an interface based on the functions and enums in this
+ * class and returns it...
+ */
+AbstractMetaClass *AbstractMetaClass::extractInterface()
+{
+ Q_ASSERT(typeEntry()->designatedInterface());
+
+ if (!m_extractedInterface) {
+ AbstractMetaClass *iface = new AbstractMetaClass;
+ iface->setAttributes(attributes());
+ iface->setBaseClass(0);
+
+ iface->setTypeEntry(typeEntry()->designatedInterface());
+
+ for (AbstractMetaFunction *function : qAsConst(m_functions)) {
+ if (!function->isConstructor())
+ iface->addFunction(function->copy());
+ }
+
+// iface->setEnums(enums());
+// setEnums(AbstractMetaEnumList());
+
+ for (const AbstractMetaField *field : qAsConst(m_fields)) {
+ if (field->isPublic()) {
+ AbstractMetaField *new_field = field->copy();
+ new_field->setEnclosingClass(iface);
+ iface->addField(new_field);
+ }
+ }
+
+ m_extractedInterface = iface;
+ addInterface(iface);
+ }
+
+ return m_extractedInterface;
+}
+
+/*******************************************************************************
+ * Returns a list of all the functions with a given name
+ */
+AbstractMetaFunctionList AbstractMetaClass::queryFunctionsByName(const QString &name) const
+{
+ AbstractMetaFunctionList returned;
+ for (AbstractMetaFunction *function : m_functions) {
+ if (function->name() == name)
+ returned.append(function);
+ }
+
+ return returned;
+}
+
+/*******************************************************************************
+ * Returns a list of all the functions retrieved during parsing which should
+ * be added to the API.
+ */
+AbstractMetaFunctionList AbstractMetaClass::functionsInTargetLang() const
+{
+ FunctionQueryOptions default_flags = NormalFunctions | Visible | NotRemovedFromTargetLang;
+
+ // Interfaces don't implement functions
+ if (isInterface())
+ default_flags |= ClassImplements;
+
+ // Only public functions in final classes
+ // default_flags |= isFinal() ? WasPublic : 0;
+ FunctionQueryOptions public_flags;
+ if (isFinal())
+ public_flags |= WasPublic;
+
+ // Constructors
+ AbstractMetaFunctionList returned = queryFunctions(Constructors | default_flags | public_flags);
+
+ // Final functions
+ returned += queryFunctions(FinalInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags);
+
+ // Virtual functions
+ returned += queryFunctions(VirtualInTargetLangFunctions | NonStaticFunctions | default_flags | public_flags);
+
+ // Static functions
+ returned += queryFunctions(StaticFunctions | default_flags | public_flags);
+
+ // Empty, private functions, since they aren't caught by the other ones
+ returned += queryFunctions(Empty | Invisible);
+
+ return returned;
+}
+
+AbstractMetaFunctionList AbstractMetaClass::virtualFunctions() const
+{
+ const AbstractMetaFunctionList &list = functionsInShellClass();
+
+ AbstractMetaFunctionList returned;
+ for (AbstractMetaFunction *f : list) {
+ if (!f->isFinalInCpp() || f->isVirtualSlot())
+ returned += f;
+ }
+
+ return returned;
+}
+
+AbstractMetaFunctionList AbstractMetaClass::implicitConversions() const
+{
+ if (!hasCloneOperator() && !hasExternalConversionOperators())
+ return AbstractMetaFunctionList();
+
+ AbstractMetaFunctionList returned;
+ const AbstractMetaFunctionList list = queryFunctions(Constructors) + externalConversionOperators();
+
+ // Exclude anything that uses rvalue references, be it a move
+ // constructor "QPolygon(QPolygon &&)" or something else like
+ // "QPolygon(QVector<QPoint> &&)".
+ for (AbstractMetaFunction *f : list) {
+ if ((f->actualMinimumArgumentCount() == 1 || f->arguments().size() == 1 || f->isConversionOperator())
+ && !f->isExplicit()
+ && f->functionType() != AbstractMetaFunction::CopyConstructorFunction
+ && !f->usesRValueReferences()
+ && !f->isModifiedRemoved()
+ && (f->originalAttributes() & Public)) {
+ returned += f;
+ }
+ }
+ return returned;
+}
+
+AbstractMetaFunctionList AbstractMetaClass::operatorOverloads(OperatorQueryOptions query) const
+{
+ const AbstractMetaFunctionList &list = queryFunctions(OperatorOverloads | Visible);
+ AbstractMetaFunctionList returned;
+ for (AbstractMetaFunction *f : list) {
+ if (((query & ArithmeticOp) && f->isArithmeticOperator())
+ || ((query & BitwiseOp) && f->isBitwiseOperator())
+ || ((query & ComparisonOp) && f->isComparisonOperator())
+ || ((query & LogicalOp) && f->isLogicalOperator())
+ || ((query & SubscriptionOp) && f->isSubscriptOperator())
+ || ((query & AssignmentOp) && f->isAssignmentOperator())
+ || ((query & ConversionOp) && f->isConversionOperator())
+ || ((query & OtherOp) && f->isOtherOperator()))
+ returned += f;
+ }
+
+ return returned;
+}
+
+bool AbstractMetaClass::hasOperatorOverload() const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isOperatorOverload() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasArithmeticOperatorOverload() const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isArithmeticOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasBitwiseOperatorOverload() const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isBitwiseOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasComparisonOperatorOverload() const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isComparisonOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasLogicalOperatorOverload() const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isLogicalOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasSubscriptOperatorOverload() const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isSubscriptOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasAssignmentOperatorOverload() const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isAssignmentOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasConversionOperatorOverload() const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->ownerClass() == f->implementingClass() && f->isConversionOperator() && !f->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+/*******************************************************************************
+ * Returns a list of all functions that should be declared and implemented in
+ * the shell class which is generated as a wrapper on top of the actual C++ class
+ */
+AbstractMetaFunctionList AbstractMetaClass::functionsInShellClass() const
+{
+ // Only functions and only protected and public functions
+ FunctionQueryOptions default_flags = NormalFunctions | Visible | WasVisible | NotRemovedFromShell;
+
+ // All virtual functions
+ AbstractMetaFunctionList returned = queryFunctions(VirtualFunctions | default_flags);
+
+ // All functions explicitly set to be implemented by the shell class
+ // (mainly superclass functions that are hidden by other declarations)
+ returned += queryFunctions(ForcedShellFunctions | default_flags);
+
+ // All functions explicitly set to be virtual slots
+ returned += queryFunctions(VirtualSlots | default_flags);
+
+ return returned;
+}
+
+/*******************************************************************************
+ * Returns a list of all functions that require a public override function to
+ * be generated in the shell class. This includes all functions that were originally
+ * protected in the superclass.
+ */
+AbstractMetaFunctionList AbstractMetaClass::publicOverrideFunctions() const
+{
+ return queryFunctions(NormalFunctions | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang)
+ + queryFunctions(Signals | WasProtected | FinalInCppFunctions | NotRemovedFromTargetLang);
+}
+
+AbstractMetaFunctionList AbstractMetaClass::virtualOverrideFunctions() const
+{
+ return queryFunctions(NormalFunctions | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell) +
+ queryFunctions(Signals | NonEmptyFunctions | Visible | VirtualInCppFunctions | NotRemovedFromShell);
+}
+
+void AbstractMetaClass::sortFunctions()
+{
+ qSort(m_functions.begin(), m_functions.end(), function_sorter);
+}
+
+void AbstractMetaClass::setFunctions(const AbstractMetaFunctionList &functions)
+{
+ m_functions = functions;
+
+ // Functions must be sorted by name before next loop
+ sortFunctions();
+
+ QString currentName;
+ bool hasVirtuals = false;
+ AbstractMetaFunctionList finalFunctions;
+ for (AbstractMetaFunction *f : qAsConst(m_functions)) {
+ f->setOwnerClass(this);
+
+ m_hasVirtualSlots = m_hasVirtualSlots || f->isVirtualSlot();
+ m_hasVirtuals = m_hasVirtuals || f->isVirtualSlot() || hasVirtualDestructor();
+ m_isPolymorphic = m_isPolymorphic || m_hasVirtuals;
+ m_hasNonpublic = m_hasNonpublic || !f->isPublic();
+
+ // If we have non-virtual overloads of a virtual function, we have to implement
+ // all the overloads in the shell class to override the hiding rule
+ if (currentName == f->name()) {
+ hasVirtuals = hasVirtuals || !f->isFinal();
+ if (f->isFinal())
+ finalFunctions += f;
+ } else {
+ if (hasVirtuals && finalFunctions.size() > 0) {
+ for (AbstractMetaFunction *final_function : qAsConst(finalFunctions)) {
+ *final_function += AbstractMetaAttributes::ForceShellImplementation;
+
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("hiding of function '%1' in class '%2'")
+ .arg(final_function->name(), name());
+ }
+ }
+
+ hasVirtuals = !f->isFinal();
+ finalFunctions.clear();
+ if (f->isFinal())
+ finalFunctions += f;
+ currentName = f->name();
+ }
+ }
+}
+
+bool AbstractMetaClass::hasFieldAccessors() const
+{
+ for (const AbstractMetaField *field : m_fields) {
+ if (field->getter() || field->setter())
+ return true;
+ }
+
+ return false;
+}
+
+bool AbstractMetaClass::hasDefaultToStringFunction() const
+{
+ const AbstractMetaFunctionList &funcs = queryFunctionsByName(QLatin1String("toString"));
+ for (const AbstractMetaFunction *f : funcs) {
+ if (!f->actualMinimumArgumentCount())
+ return true;
+ }
+ return false;
+}
+
+void AbstractMetaClass::addFunction(AbstractMetaFunction *function)
+{
+ Q_ASSERT(!function->signature().startsWith(QLatin1Char('(')));
+ function->setOwnerClass(this);
+
+ if (!function->isDestructor())
+ m_functions << function;
+ else
+ Q_ASSERT(false); //memory leak
+
+ m_hasVirtualSlots |= function->isVirtualSlot();
+ m_hasVirtuals |= !function->isFinal() || function->isVirtualSlot() || hasVirtualDestructor();
+ m_isPolymorphic |= m_hasVirtuals;
+ m_hasNonpublic |= !function->isPublic();
+}
+
+bool AbstractMetaClass::hasSignal(const AbstractMetaFunction *other) const
+{
+ if (!other->isSignal())
+ return false;
+
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->isSignal() && f->compareTo(other) & AbstractMetaFunction::EqualName)
+ return other->modifiedName() == f->modifiedName();
+ }
+
+ return false;
+}
+
+
+QString AbstractMetaClass::name() const
+{
+ return QString(m_typeEntry->targetLangName()).split(QLatin1String("::")).last();
+}
+
+void AbstractMetaClass::setBaseClass(AbstractMetaClass *baseClass)
+{
+ m_baseClass = baseClass;
+ if (baseClass)
+ m_isPolymorphic |= baseClass->isPolymorphic();
+}
+
+QString AbstractMetaClass::package() const
+{
+ return m_typeEntry->targetLangPackage();
+}
+
+bool AbstractMetaClass::isInterface() const
+{
+ return m_typeEntry->isInterface();
+}
+
+bool AbstractMetaClass::isNamespace() const
+{
+ return m_typeEntry->isNamespace();
+}
+
+bool AbstractMetaClass::isQObject() const
+{
+ return m_typeEntry->isQObject();
+}
+
+QString AbstractMetaClass::qualifiedCppName() const
+{
+ return m_typeEntry->qualifiedCppName();
+}
+
+bool AbstractMetaClass::hasFunction(const QString &str) const
+{
+ return findFunction(str);
+}
+
+const AbstractMetaFunction* AbstractMetaClass::findFunction(const QString& functionName) const
+{
+ for (const AbstractMetaFunction *f : m_functions) {
+ if (f->name() == functionName)
+ return f;
+ }
+ return 0;
+}
+
+bool AbstractMetaClass::hasProtectedFunctions() const
+{
+ for (AbstractMetaFunction *func : m_functions) {
+ if (func->isProtected())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasProtectedFields() const
+{
+ for (const AbstractMetaField *field : m_fields) {
+ if (field->isProtected())
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasProtectedMembers() const
+{
+ return hasProtectedFields() || hasProtectedFunctions();
+}
+
+bool AbstractMetaClass::generateShellClass() const
+{
+ return m_forceShellClass ||
+ (!isFinal()
+ && (hasVirtualFunctions()
+ || hasProtectedFunctions()
+ || hasFieldAccessors()));
+}
+
+QPropertySpec *AbstractMetaClass::propertySpecForRead(const QString &name) const
+{
+ for (int i = 0; i < m_propertySpecs.size(); ++i)
+ if (name == m_propertySpecs.at(i)->read())
+ return m_propertySpecs.at(i);
+ return 0;
+}
+
+QPropertySpec *AbstractMetaClass::propertySpecForWrite(const QString &name) const
+{
+ for (int i = 0; i < m_propertySpecs.size(); ++i)
+ if (name == m_propertySpecs.at(i)->write())
+ return m_propertySpecs.at(i);
+ return 0;
+}
+
+QPropertySpec *AbstractMetaClass::propertySpecForReset(const QString &name) const
+{
+ for (int i = 0; i < m_propertySpecs.size(); ++i) {
+ if (name == m_propertySpecs.at(i)->reset())
+ return m_propertySpecs.at(i);
+ }
+ return 0;
+}
+
+typedef QHash<const AbstractMetaClass*, AbstractMetaTypeList> AbstractMetaClassBaseTemplateInstantiationsMap;
+Q_GLOBAL_STATIC(AbstractMetaClassBaseTemplateInstantiationsMap, metaClassBaseTemplateInstantiations);
+
+bool AbstractMetaClass::hasTemplateBaseClassInstantiations() const
+{
+ if (!templateBaseClass())
+ return false;
+ return metaClassBaseTemplateInstantiations()->contains(this);
+}
+
+AbstractMetaTypeList AbstractMetaClass::templateBaseClassInstantiations() const
+{
+ if (!templateBaseClass())
+ return AbstractMetaTypeList();
+ return metaClassBaseTemplateInstantiations()->value(this);
+}
+
+void AbstractMetaClass::setTemplateBaseClassInstantiations(AbstractMetaTypeList& instantiations)
+{
+ if (!templateBaseClass())
+ return;
+ metaClassBaseTemplateInstantiations()->insert(this, instantiations);
+}
+
+static bool functions_contains(const AbstractMetaFunctionList &l, const AbstractMetaFunction *func)
+{
+ for (const AbstractMetaFunction *f : l) {
+ if ((f->compareTo(func) & AbstractMetaFunction::PrettySimilar) == AbstractMetaFunction::PrettySimilar)
+ return true;
+ }
+ return false;
+}
+
+AbstractMetaField::AbstractMetaField() : m_getter(0), m_setter(0), m_class(0)
+{
+}
+
+AbstractMetaField::~AbstractMetaField()
+{
+ delete m_setter;
+ delete m_getter;
+}
+
+AbstractMetaField *AbstractMetaField::copy() const
+{
+ AbstractMetaField *returned = new AbstractMetaField;
+ returned->setEnclosingClass(0);
+ returned->setAttributes(attributes());
+ returned->setName(name());
+ returned->setType(type()->copy());
+ returned->setOriginalAttributes(originalAttributes());
+
+ return returned;
+}
+
+/*******************************************************************************
+ * Indicates that this field has a modification that removes it
+ */
+bool AbstractMetaField::isModifiedRemoved(int types) const
+{
+ const FieldModificationList &mods = modifications();
+ for (const FieldModification &mod : mods) {
+ if (!mod.isRemoveModifier())
+ continue;
+
+ if ((mod.removal & types) == types)
+ return true;
+ }
+
+ return false;
+}
+
+static QString upCaseFirst(const QString &str)
+{
+ Q_ASSERT(!str.isEmpty());
+ QString s = str;
+ s[0] = s.at(0).toUpper();
+ return s;
+}
+
+static AbstractMetaFunction *createXetter(const AbstractMetaField *g, const QString &name,
+ AbstractMetaAttributes::Attributes type)
+{
+ AbstractMetaFunction *f = new AbstractMetaFunction;
+
+ f->setName(name);
+ f->setOriginalName(name);
+ f->setOwnerClass(g->enclosingClass());
+ f->setImplementingClass(g->enclosingClass());
+ f->setDeclaringClass(g->enclosingClass());
+
+ AbstractMetaAttributes::Attributes attr = AbstractMetaAttributes::Native
+ | AbstractMetaAttributes::Final
+ | type;
+ if (g->isStatic())
+ attr |= AbstractMetaAttributes::Static;
+ if (g->isPublic())
+ attr |= AbstractMetaAttributes::Public;
+ else if (g->isProtected())
+ attr |= AbstractMetaAttributes::Protected;
+ else
+ attr |= AbstractMetaAttributes::Private;
+ f->setAttributes(attr);
+ f->setOriginalAttributes(attr);
+
+ const FieldModificationList &mods = g->modifications();
+ for (const FieldModification &mod : mods) {
+ if (mod.isRenameModifier())
+ f->setName(mod.renamedTo());
+ if (mod.isAccessModifier()) {
+ if (mod.isPrivate())
+ f->setVisibility(AbstractMetaAttributes::Private);
+ else if (mod.isProtected())
+ f->setVisibility(AbstractMetaAttributes::Protected);
+ else if (mod.isPublic())
+ f->setVisibility(AbstractMetaAttributes::Public);
+ else if (mod.isFriendly())
+ f->setVisibility(AbstractMetaAttributes::Friendly);
+ }
+ }
+ return f;
+}
+
+FieldModificationList AbstractMetaField::modifications() const
+{
+ const FieldModificationList &mods = enclosingClass()->typeEntry()->fieldModifications();
+ FieldModificationList returned;
+
+ for (const FieldModification &mod : mods) {
+ if (mod.name == name())
+ returned += mod;
+ }
+
+ return returned;
+}
+
+const AbstractMetaFunction *AbstractMetaField::setter() const
+{
+ if (!m_setter) {
+ m_setter = createXetter(this,
+ QLatin1String("set") + upCaseFirst(name()),
+ AbstractMetaAttributes::SetterFunction);
+ AbstractMetaArgumentList arguments;
+ AbstractMetaArgument *argument = new AbstractMetaArgument;
+ argument->setType(type()->copy());
+ argument->setName(name());
+ arguments.append(argument);
+ m_setter->setArguments(arguments);
+ }
+ return m_setter;
+}
+
+const AbstractMetaFunction *AbstractMetaField::getter() const
+{
+ if (!m_getter) {
+ m_getter = createXetter(this,
+ name(),
+ AbstractMetaAttributes::GetterFunction);
+ m_getter->setType(type());
+ }
+
+ return m_getter;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+static void formatMetaAttributes(QDebug &d, AbstractMetaAttributes::Attributes value)
+{
+ static const int meIndex = AbstractMetaAttributes::staticMetaObject.indexOfEnumerator("Attribute");
+ Q_ASSERT(meIndex >= 0);
+ const QMetaEnum me = AbstractMetaAttributes::staticMetaObject.enumerator(meIndex);
+ d << me.valueToKeys(value);
+}
+
+static void formatMetaField(QDebug &d, const AbstractMetaField *af)
+{
+ formatMetaAttributes(d, af->attributes());
+ d << ' ' << af->type()->name() << " \"" << af->name() << '"';
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaField *af)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaField(";
+ if (af)
+ formatMetaField(d, af);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+
+static void formatMetaEnumValue(QDebug &d, const AbstractMetaEnumValue *v)
+{
+ const QString &name = v->stringValue();
+ if (!name.isEmpty())
+ d << name << '=';
+ d << v->value();
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaEnumValue *v)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaEnumValue(";
+ if (v)
+ formatMetaEnumValue(d, v);
+ else
+ d << '0';
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AbstractMetaEnum *ae)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaEnum(";
+ if (ae) {
+ d << ae->fullName() << '[';
+ const AbstractMetaEnumValueList &values = ae->values();
+ for (int i = 0, count = values.size(); i < count; ++i) {
+ if (i)
+ d << ' ';
+ formatMetaEnumValue(d, values.at(i));
+ }
+ d << ']';
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+bool AbstractMetaClass::hasConstructors() const
+{
+ return queryFunctions(Constructors).size();
+}
+
+bool AbstractMetaClass::hasCopyConstructor() const
+{
+ const AbstractMetaFunctionList &ctors = queryFunctions(Constructors);
+ for (const AbstractMetaFunction* ctor : ctors) {
+ if (ctor->functionType() == AbstractMetaFunction::CopyConstructorFunction)
+ return true;
+ }
+ return false;
+}
+
+bool AbstractMetaClass::hasPrivateCopyConstructor() const
+{
+ const AbstractMetaFunctionList &ctors = queryFunctions(Constructors);
+ for (const AbstractMetaFunction *ctor : ctors) {
+ if (ctor->functionType() == AbstractMetaFunction::CopyConstructorFunction && ctor->isPrivate())
+ return true;
+ }
+ return false;
+}
+
+void AbstractMetaClass::addDefaultConstructor()
+{
+ AbstractMetaFunction *f = new AbstractMetaFunction;
+ f->setOriginalName(name());
+ f->setName(name());
+ f->setOwnerClass(this);
+ f->setFunctionType(AbstractMetaFunction::ConstructorFunction);
+ f->setArguments(AbstractMetaArgumentList());
+ f->setDeclaringClass(this);
+
+ AbstractMetaAttributes::Attributes attr = AbstractMetaAttributes::Native;
+ attr |= AbstractMetaAttributes::Public;
+ attr |= AbstractMetaAttributes::Final;
+ f->setAttributes(attr);
+ f->setImplementingClass(this);
+ f->setOriginalAttributes(f->attributes());
+
+ addFunction(f);
+ this->setHasNonPrivateConstructor(true);
+}
+
+void AbstractMetaClass::addDefaultCopyConstructor(bool isPrivate)
+{
+ AbstractMetaFunction* f = new AbstractMetaFunction;
+ f->setOriginalName(name());
+ f->setName(name());
+ f->setOwnerClass(this);
+ f->setFunctionType(AbstractMetaFunction::CopyConstructorFunction);
+ f->setDeclaringClass(this);
+
+ AbstractMetaType* argType = new AbstractMetaType;
+ argType->setTypeEntry(typeEntry());
+ argType->setReferenceType(LValueReference);
+ argType->setConstant(true);
+ argType->setTypeUsagePattern(AbstractMetaType::ValuePattern);
+
+ AbstractMetaArgument* arg = new AbstractMetaArgument;
+ arg->setType(argType);
+ arg->setName(name());
+ f->addArgument(arg);
+
+ AbstractMetaAttributes::Attributes attr = AbstractMetaAttributes::Native;
+ attr |= AbstractMetaAttributes::Final;
+ if (isPrivate)
+ attr |= AbstractMetaAttributes::Private;
+ else
+ attr |= AbstractMetaAttributes::Public;
+ f->setAttributes(attr);
+ f->setImplementingClass(this);
+ f->setOriginalAttributes(f->attributes());
+
+ addFunction(f);
+}
+
+bool AbstractMetaClass::hasFunction(const AbstractMetaFunction *f) const
+{
+ return functions_contains(m_functions, f);
+}
+
+/* Goes through the list of functions and returns a list of all
+ functions matching all of the criteria in \a query.
+ */
+
+AbstractMetaFunctionList AbstractMetaClass::queryFunctions(FunctionQueryOptions query) const
+{
+ AbstractMetaFunctionList functions;
+
+ for (AbstractMetaFunction *f : m_functions) {
+
+ if ((query & VirtualSlots) && !f->isVirtualSlot())
+ continue;
+
+ if ((query & NotRemovedFromTargetLang) && f->isRemovedFrom(f->implementingClass(), TypeSystem::TargetLangCode))
+ continue;
+
+ if ((query & NotRemovedFromTargetLang) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::TargetLangCode))
+ continue;
+
+ if ((query & NotRemovedFromShell) && f->isRemovedFrom(f->implementingClass(), TypeSystem::ShellCode))
+ continue;
+
+ if ((query & NotRemovedFromShell) && !f->isFinal() && f->isRemovedFrom(f->declaringClass(), TypeSystem::ShellCode))
+ continue;
+
+ if ((query & Visible) && f->isPrivate())
+ continue;
+
+ if ((query & VirtualInTargetLangFunctions) && f->isFinalInTargetLang())
+ continue;
+
+ if ((query & Invisible) && !f->isPrivate())
+ continue;
+
+ if ((query & Empty) && !f->isEmptyFunction())
+ continue;
+
+ if ((query & WasPublic) && !f->wasPublic())
+ continue;
+
+ if ((query & WasVisible) && f->wasPrivate())
+ continue;
+
+ if ((query & WasProtected) && !f->wasProtected())
+ continue;
+
+ if ((query & ClassImplements) && f->ownerClass() != f->implementingClass())
+ continue;
+
+ if ((query & Inconsistent) && (f->isFinalInTargetLang() || !f->isFinalInCpp() || f->isStatic()))
+ continue;
+
+ if ((query & FinalInTargetLangFunctions) && !f->isFinalInTargetLang())
+ continue;
+
+ if ((query & FinalInCppFunctions) && !f->isFinalInCpp())
+ continue;
+
+ if ((query & VirtualInCppFunctions) && f->isFinalInCpp())
+ continue;
+
+ if ((query & Signals) && (!f->isSignal()))
+ continue;
+
+ if ((query & ForcedShellFunctions) &&
+ (!f->isForcedShellImplementation() || !f->isFinal())) {
+ continue;
+ }
+
+ if ((query & Constructors) && (!f->isConstructor() || f->ownerClass() != f->implementingClass()))
+ continue;
+
+ if (!(query & Constructors) && f->isConstructor())
+ continue;
+
+ // Destructors are never included in the functions of a class currently
+ /*
+ if ((query & Destructors) && (!f->isDestructor()
+ || f->ownerClass() != f->implementingClass())
+ || f->isDestructor() && (query & Destructors) == 0) {
+ continue;
+ }*/
+
+ if ((query & VirtualFunctions) && (f->isFinal() || f->isSignal() || f->isStatic()))
+ continue;
+
+ if ((query & StaticFunctions) && (!f->isStatic() || f->isSignal()))
+ continue;
+
+ if ((query & NonStaticFunctions) && (f->isStatic()))
+ continue;
+
+ if ((query & NonEmptyFunctions) && (f->isEmptyFunction()))
+ continue;
+
+ if ((query & NormalFunctions) && (f->isSignal()))
+ continue;
+
+ if ((query & AbstractFunctions) && !f->isAbstract())
+ continue;
+
+ if ((query & OperatorOverloads) && !f->isOperatorOverload())
+ continue;
+
+ functions << f;
+ }
+
+ return functions;
+}
+
+bool AbstractMetaClass::hasSignals() const
+{
+ return cppSignalFunctions().size() > 0;
+}
+
+
+/**
+ * Adds the specified interface to this class by adding all the
+ * functions in the interface to this class.
+ */
+void AbstractMetaClass::addInterface(AbstractMetaClass *interface)
+{
+ Q_ASSERT(!m_interfaces.contains(interface));
+ m_interfaces << interface;
+
+ m_isPolymorphic |= interface->isPolymorphic();
+
+ if (m_extractedInterface && m_extractedInterface != interface)
+ m_extractedInterface->addInterface(interface);
+
+
+#if 0
+ const AbstractMetaFunctionList &funcs = interface->functions();
+ for (AbstractMetaFunction *function : funcs)
+ if (!hasFunction(function) && !function->isConstructor()) {
+ AbstractMetaFunction *cpy = function->copy();
+ cpy->setImplementingClass(this);
+
+ // Setup that this function is an interface class.
+ cpy->setInterfaceClass(interface);
+ *cpy += AbstractMetaAttributes::InterfaceFunction;
+
+ // Copy the modifications in interface into the implementing classes.
+ const FunctionModificationList &mods = function->modifications(interface);
+ for (const FunctionModification &mod : mods)
+ m_typeEntry->addFunctionModification(mod);
+
+ // It should be mostly safe to assume that when we implement an interface
+ // we don't "pass on" pure virtual functions to our sublcasses...
+// *cpy -= AbstractMetaAttributes::Abstract;
+
+ addFunction(cpy);
+ }
+#endif
+
+}
+
+
+void AbstractMetaClass::setInterfaces(const AbstractMetaClassList &interfaces)
+{
+ m_interfaces = interfaces;
+ for (const AbstractMetaClass *interface : interfaces) {
+ if (interface)
+ m_isPolymorphic |= interface->isPolymorphic();
+ }
+}
+
+
+AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName)
+{
+ for (AbstractMetaEnum *e : qAsConst(m_enums)) {
+ if (e->name() == enumName)
+ return e;
+ }
+
+ if (typeEntry()->designatedInterface())
+ return extractInterface()->findEnum(enumName);
+
+ return 0;
+}
+
+
+
+
+/*! Recursivly searches for the enum value named \a enumValueName in
+ this class and its superclasses and interfaces. Values belonging to
+ \a meta_enum are excluded from the search.
+*/
+AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const QString &enumValueName, AbstractMetaEnum *meta_enum)
+{
+ for (AbstractMetaEnum *e : qAsConst(m_enums)) {
+ if (e != meta_enum)
+ continue;
+ const AbstractMetaEnumValueList &values = e->values();
+ for (AbstractMetaEnumValue *v : values) {
+ if (v->name() == enumValueName)
+ return v;
+ }
+ }
+
+ if (typeEntry()->designatedInterface())
+ return extractInterface()->findEnumValue(enumValueName, meta_enum);
+
+ if (baseClass())
+ return baseClass()->findEnumValue(enumValueName, meta_enum);
+
+ return 0;
+}
+
+
+/*!
+ * Searches through all of this class' enums for a value matching the
+ * name \a enumValueName. The name is excluding the class/namespace
+ * prefix. The function recursivly searches interfaces and baseclasses
+ * of this class.
+ */
+AbstractMetaEnum *AbstractMetaClass::findEnumForValue(const QString &enumValueName)
+{
+ for (AbstractMetaEnum *e : qAsConst(m_enums)) {
+ const AbstractMetaEnumValueList &values = e->values();
+ for (AbstractMetaEnumValue *v : values) {
+ if (v->name() == enumValueName)
+ return e;
+ }
+ }
+
+ if (typeEntry()->designatedInterface())
+ return extractInterface()->findEnumForValue(enumValueName);
+
+ if (baseClass())
+ return baseClass()->findEnumForValue(enumValueName);
+
+ return 0;
+}
+
+
+static void addExtraIncludeForType(AbstractMetaClass *metaClass, const AbstractMetaType *type)
+{
+ if (!type)
+ return;
+
+ Q_ASSERT(metaClass);
+ const TypeEntry *entry = (type ? type->typeEntry() : 0);
+ if (entry && entry->isComplex()) {
+ const ComplexTypeEntry *centry = static_cast<const ComplexTypeEntry *>(entry);
+ ComplexTypeEntry *class_entry = metaClass->typeEntry();
+ if (class_entry && centry->include().isValid())
+ class_entry->addExtraInclude(centry->include());
+ }
+
+ if (type->hasInstantiations()) {
+ const AbstractMetaTypeList &instantiations = type->instantiations();
+ for (const AbstractMetaType *instantiation : instantiations)
+ addExtraIncludeForType(metaClass, instantiation);
+ }
+}
+
+static void addExtraIncludesForFunction(AbstractMetaClass *metaClass, const AbstractMetaFunction *meta_function)
+{
+ Q_ASSERT(metaClass);
+ Q_ASSERT(meta_function);
+ addExtraIncludeForType(metaClass, meta_function->type());
+
+ const AbstractMetaArgumentList &arguments = meta_function->arguments();
+ for (AbstractMetaArgument *argument : arguments)
+ addExtraIncludeForType(metaClass, argument->type());
+}
+
+void AbstractMetaClass::fixFunctions()
+{
+ if (m_functionsFixed)
+ return;
+ else
+ m_functionsFixed = true;
+
+ AbstractMetaClass *superClass = baseClass();
+ AbstractMetaFunctionList funcs = functions();
+
+ if (superClass)
+ superClass->fixFunctions();
+ int iface_idx = 0;
+ while (superClass || iface_idx < interfaces().size()) {
+ // Since we always traverse the complete hierarchy we are only
+ // interrested in what each super class implements, not what
+ // we may have propagated from their base classes again.
+ AbstractMetaFunctionList superFuncs;
+ if (superClass) {
+ // Super classes can never be final
+ if (superClass->isFinalInTargetLang()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Final class '" << superClass->name() << "' set to non-final, as it is extended by other classes";
+ *superClass -= AbstractMetaAttributes::FinalInTargetLang;
+ }
+ superFuncs = superClass->queryFunctions(AbstractMetaClass::ClassImplements);
+ AbstractMetaFunctionList virtuals = superClass->queryFunctions(AbstractMetaClass::VirtualInCppFunctions);
+ superFuncs += virtuals;
+ } else {
+ superFuncs = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::NormalFunctions);
+ AbstractMetaFunctionList virtuals = interfaces().at(iface_idx)->queryFunctions(AbstractMetaClass::VirtualInCppFunctions);
+ superFuncs += virtuals;
+ }
+
+ QSet<AbstractMetaFunction *> funcsToAdd;
+ for (int sfi = 0; sfi < superFuncs.size(); ++sfi) {
+ AbstractMetaFunction *sf = superFuncs.at(sfi);
+
+ if (sf->isRemovedFromAllLanguages(sf->implementingClass()))
+ continue;
+
+ // skip functions added in base classes
+ if (sf->isUserAdded() && sf->declaringClass() != this)
+ continue;
+
+ // we generally don't care about private functions, but we have to get the ones that are
+ // virtual in case they override abstract functions.
+ bool add = (sf->isNormal() || sf->isSignal() || sf->isEmptyFunction());
+ for (int fi = 0; fi < funcs.size(); ++fi) {
+ AbstractMetaFunction *f = funcs.at(fi);
+ if (f->isRemovedFromAllLanguages(f->implementingClass()))
+ continue;
+
+
+ const AbstractMetaFunction::CompareResult cmp = f->compareTo(sf);
+
+ if (cmp & AbstractMetaFunction::EqualModifiedName) {
+ add = false;
+ if (cmp & AbstractMetaFunction::EqualArguments) {
+ // Same function, propegate virtual...
+ if (!(cmp & AbstractMetaFunction::EqualAttributes)) {
+ if (!f->isEmptyFunction()) {
+ if (!sf->isFinalInCpp() && f->isFinalInCpp()) {
+ *f -= AbstractMetaAttributes::FinalInCpp;
+ }
+ if (!sf->isFinalInTargetLang() && f->isFinalInTargetLang()) {
+ *f -= AbstractMetaAttributes::FinalInTargetLang;
+ }
+#if 0
+ if (!f->isFinalInTargetLang() && f->isPrivate()) {
+ f->setFunctionType(AbstractMetaFunction::EmptyFunction);
+ f->setVisibility(AbstractMetaAttributes::Protected);
+ *f += AbstractMetaAttributes::FinalInTargetLang;
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("private virtual function '%1' in '%2'")
+ .arg(f->signature(), f->implementingClass()->name());
+ }
+#endif
+ }
+ }
+
+ if (f->visibility() != sf->visibility()) {
+ QString warn = QStringLiteral("visibility of function '%1' modified in class '%2'")
+ .arg(f->name(), name());
+ qCWarning(lcShiboken).noquote().nospace() << warn;
+#if 0
+ // If new visibility is private, we can't
+ // do anything. If it isn't, then we
+ // prefer the parent class's visibility
+ // setting for the function.
+ if (!f->isPrivate() && !sf->isPrivate())
+ f->setVisibility(sf->visibility());
+#endif
+ // Private overrides of abstract functions have to go into the class or
+ // the subclasses will not compile as non-abstract classes.
+ // But they don't need to be implemented, since they can never be called.
+ if (f->isPrivate()) {
+ f->setFunctionType(AbstractMetaFunction::EmptyFunction);
+ *f += AbstractMetaAttributes::FinalInTargetLang;
+ *f += AbstractMetaAttributes::FinalInCpp;
+ }
+ }
+
+ // Set the class which first declares this function, afawk
+ f->setDeclaringClass(sf->declaringClass());
+
+ if (sf->isFinalInTargetLang() && !sf->isPrivate() && !f->isPrivate() && !sf->isStatic() && !f->isStatic()) {
+ // Shadowed funcion, need to make base class
+ // function non-virtual
+ if (f->implementingClass() != sf->implementingClass() && f->implementingClass()->inheritsFrom(sf->implementingClass())) {
+
+ // Check whether the superclass method has been redefined to non-final
+
+ bool hasNonFinalModifier = false;
+ bool isBaseImplPrivate = false;
+ const FunctionModificationList &mods = sf->modifications(sf->implementingClass());
+ for (const FunctionModification &mod : mods) {
+ if (mod.isNonFinal()) {
+ hasNonFinalModifier = true;
+ break;
+ } else if (mod.isPrivate()) {
+ isBaseImplPrivate = true;
+ break;
+ }
+ }
+
+ if (!hasNonFinalModifier && !isBaseImplPrivate) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Shadowing: %1::%2 and %3::%4")
+ .arg(sf->implementingClass()->name(), sf->signature(),
+ f->implementingClass()->name(), f->signature());
+ }
+ }
+ }
+
+ }
+
+ if (cmp & AbstractMetaFunction::EqualDefaultValueOverload) {
+ AbstractMetaArgumentList arguments;
+ if (f->arguments().size() < sf->arguments().size())
+ arguments = sf->arguments();
+ else
+ arguments = f->arguments();
+ //TODO: fix this
+ //for (int i=0; i<arguments.size(); ++i)
+ // arguments[i]->setDefaultValueExpression("<#>" + QString());
+ }
+
+
+ // Otherwise we have function shadowing and we can
+ // skip the thing...
+ } else if (cmp & AbstractMetaFunction::EqualName && !sf->isSignal()) {
+ // In the case of function shadowing where the function name has been altered to
+ // avoid conflict, we don't copy in the original.
+ add = false;
+ }
+ }
+
+ if (add)
+ funcsToAdd << sf;
+ }
+
+ for (AbstractMetaFunction *f : qAsConst(funcsToAdd))
+ funcs << f->copy();
+
+ if (superClass)
+ superClass = superClass->baseClass();
+ else
+ iface_idx++;
+ }
+
+ bool hasPrivateConstructors = false;
+ bool hasPublicConstructors = false;
+ for (AbstractMetaFunction *func : qAsConst(funcs)) {
+ const FunctionModificationList &mods = func->modifications(this);
+ for (const FunctionModification &mod : mods) {
+ if (mod.isRenameModifier()) {
+ func->setName(mod.renamedTo());
+ }
+ }
+
+ // Make sure class is abstract if one of the functions is
+ if (func->isAbstract()) {
+ (*this) += AbstractMetaAttributes::Abstract;
+ (*this) -= AbstractMetaAttributes::Final;
+ }
+
+ if (func->isConstructor()) {
+ if (func->isPrivate())
+ hasPrivateConstructors = true;
+ else
+ hasPublicConstructors = true;
+ }
+
+
+
+ // Make sure that we include files for all classes that are in use
+
+ if (!func->isRemovedFrom(this, TypeSystem::ShellCode))
+ addExtraIncludesForFunction(this, func);
+ }
+
+ if (hasPrivateConstructors && !hasPublicConstructors) {
+ (*this) += AbstractMetaAttributes::Abstract;
+ (*this) -= AbstractMetaAttributes::Final;
+ }
+
+ for (AbstractMetaFunction *f1 : qAsConst(funcs)) {
+ for (AbstractMetaFunction *f2 : qAsConst(funcs)) {
+ if (f1 != f2) {
+ const AbstractMetaFunction::CompareResult cmp = f1->compareTo(f2);
+ if ((cmp & AbstractMetaFunction::EqualName)
+ && !f1->isFinalInCpp()
+ && f2->isFinalInCpp()) {
+ *f2 += AbstractMetaAttributes::FinalOverload;
+ }
+ }
+ }
+ }
+
+ setFunctions(funcs);
+}
+
+
+QString AbstractMetaType::minimalSignature() const
+{
+ QString minimalSignature;
+ if (isConstant())
+ minimalSignature += QLatin1String("const ");
+ minimalSignature += typeEntry()->qualifiedCppName();
+ if (hasInstantiations()) {
+ AbstractMetaTypeList instantiations = this->instantiations();
+ minimalSignature += QLatin1String("< ");
+ for (int i = 0; i < instantiations.size(); ++i) {
+ if (i > 0)
+ minimalSignature += QLatin1Char(',');
+ minimalSignature += instantiations[i]->minimalSignature();
+ }
+ minimalSignature += QLatin1String(" >");
+ }
+
+ for (int j = 0; j < indirections(); ++j)
+ minimalSignature += QLatin1Char('*');
+ switch (referenceType()) {
+ case NoReference:
+ break;
+ case LValueReference:
+ minimalSignature += QLatin1Char('&');
+ break;
+ case RValueReference:
+ minimalSignature += QLatin1String("&&");
+ break;
+ }
+
+ return minimalSignature;
+}
+
+bool AbstractMetaType::hasNativeId() const
+{
+ return (isQObject() || isValue() || isObject()) && typeEntry()->isNativeIdBased();
+}
+
+bool AbstractMetaType::isTargetLangEnum() const
+{
+ return isEnum() && !static_cast<const EnumTypeEntry *>(typeEntry())->forceInteger();
+}
+
+bool AbstractMetaType::isTargetLangFlags() const
+{
+ return isFlags() && !static_cast<const FlagsTypeEntry *>(typeEntry())->forceInteger();
+}
+
+
+/*******************************************************************************
+ * Other stuff...
+ */
+
+
+AbstractMetaEnum *AbstractMetaClass::findEnum(const AbstractMetaClassList &classes,
+ const EnumTypeEntry *entry)
+{
+ Q_ASSERT(entry->isEnum());
+
+ QString qualifiedName = entry->qualifiedCppName();
+ int pos = qualifiedName.lastIndexOf(QLatin1String("::"));
+
+ QString enumName;
+ QString className;
+
+ if (pos > 0) {
+ enumName = qualifiedName.mid(pos + 2);
+ className = qualifiedName.mid(0, pos);
+ } else {
+ enumName = qualifiedName;
+ className = TypeDatabase::globalNamespaceClassName(entry);
+ }
+
+ AbstractMetaClass *metaClass = AbstractMetaClass::findClass(classes, className);
+ if (!metaClass) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("AbstractMeta::findEnum(), unknown class '%1' in '%2'")
+ .arg(className, entry->qualifiedCppName());
+ return 0;
+ }
+
+ return metaClass->findEnum(enumName);
+}
+
+AbstractMetaEnumValue *AbstractMetaClass::findEnumValue(const AbstractMetaClassList &classes,
+ const QString &name)
+{
+ QStringList lst = name.split(QLatin1String("::"));
+
+ if (lst.size() > 1) {
+ QString prefixName = lst.at(0);
+ QString enumName = lst.at(1);
+
+ AbstractMetaClass* cl = findClass(classes, prefixName);
+ if (cl)
+ return cl->findEnumValue(enumName, 0);
+ }
+
+ for (AbstractMetaClass *metaClass : classes) {
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (AbstractMetaEnum *metaEnum : enums) {
+ AbstractMetaEnumValue* enumValue = metaClass->findEnumValue(name, metaEnum);
+ if (enumValue)
+ return enumValue;
+ }
+ }
+
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("no matching enum '%1'").arg(name);
+ return 0;
+}
+
+/*!
+ * Searches the list after a class that mathces \a name; either as
+ * C++, Target language base name or complete Target language package.class name.
+ */
+
+AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes,
+ const QString &name)
+{
+ if (name.isEmpty())
+ return 0;
+
+ for (AbstractMetaClass *c : classes) {
+ if (c->qualifiedCppName() == name)
+ return c;
+ }
+
+ for (AbstractMetaClass *c : classes) {
+ if (c->fullName() == name)
+ return c;
+ }
+
+ for (AbstractMetaClass *c : classes) {
+ if (c->name() == name)
+ return c;
+ }
+
+ return 0;
+}
+
+AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes,
+ const TypeEntry* typeEntry)
+{
+ for (AbstractMetaClass* c : classes) {
+ if (c->typeEntry() == typeEntry)
+ return c;
+ }
+ return 0;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaClass *ac)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AbstractMetaClass(";
+ if (ac) {
+ d << '"' << ac->fullName() << '"';
+ if (ac->m_baseClass)
+ d << ", inherits \"" << ac->m_baseClass->name() << '"';
+ const AbstractMetaEnumList &enums = ac->enums();
+ if (!enums.isEmpty())
+ d << ", enums[" << enums.size() << "]=" << enums;
+ const AbstractMetaFunctionList &functions = ac->functions();
+ if (!functions.isEmpty()) {
+ const int count = functions.size();
+ d << ", functions=[" << count << "](";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << ", ";
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
+ if (d.verbosity() > 2)
+ d << functions.at(i);
+ else
+#endif
+ formatMetaFunctionBrief(d, functions.at(i));
+ }
+ d << ')';
+ }
+ const AbstractMetaFieldList &fields = ac->fields();
+ if (!fields.isEmpty()) {
+ const int count = fields.size();
+ d << ", fields=[" << count << "](";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << ", ";
+ formatMetaField(d, fields.at(i));
+ }
+ d << ')';
+ }
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+QString AbstractMetaEnum::name() const
+{
+ return m_typeEntry->targetLangName();
+}
+
+QString AbstractMetaEnum::qualifier() const
+{
+ return m_typeEntry->targetLangQualifier();
+}
+
+QString AbstractMetaEnum::package() const
+{
+ return m_typeEntry->targetLangPackage();
+}
+
+bool AbstractMetaEnum::isAnonymous() const
+{
+ return m_typeEntry->isAnonymous();
+}
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang.h b/sources/shiboken2/ApiExtractor/abstractmetalang.h
new file mode 100644
index 000000000..4d6d5fb1f
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h
@@ -0,0 +1,1976 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ABSTRACTMETALANG_H
+#define ABSTRACTMETALANG_H
+
+#include "abstractmetalang_typedefs.h"
+#include "typesystem_enums.h"
+#include "typesystem_typedefs.h"
+
+#include "parser/codemodel_enums.h"
+
+#include <QtCore/qobjectdefs.h>
+#include <QtCore/QStringList>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+class AbstractMeta;
+class AbstractMetaClass;
+class AbstractMetaField;
+class AbstractMetaFunction;
+class AbstractMetaType;
+class AbstractMetaVariable;
+class AbstractMetaArgument;
+class AbstractMetaEnumValue;
+class AbstractMetaEnum;
+class QPropertySpec;
+
+class CodeSnip;
+class ComplexTypeEntry;
+class EnumTypeEntry;
+class FlagsTypeEntry;
+class FunctionTypeEntry;
+class TypeEntry;
+
+struct ArgumentOwner;
+struct FieldModification;
+struct FunctionModification;
+struct ReferenceCount;
+
+class Documentation
+{
+public:
+ enum Format {
+ Native,
+ Target
+ };
+
+ Documentation()
+ : m_format(Documentation::Native) {}
+
+ Documentation(const QString& value, Format fmt = Documentation::Native)
+ : m_data(value), m_format(fmt) {}
+
+ QString value() const
+ {
+ return m_data;
+ }
+
+ void setValue(const QString& value, Format fmt = Documentation::Native)
+ {
+ m_data = value; m_format = fmt;
+ }
+
+ Documentation::Format format() const
+ {
+ return m_format;
+ }
+
+private:
+ QString m_data;
+ Format m_format;
+
+};
+
+class AbstractMetaAttributes
+{
+ Q_GADGET
+public:
+ AbstractMetaAttributes() : m_attributes(0), m_originalAttributes(0) {};
+
+ enum Attribute {
+ None = 0x00000000,
+
+ Private = 0x00000001,
+ Protected = 0x00000002,
+ Public = 0x00000004,
+ Friendly = 0x00000008,
+ Visibility = 0x0000000f,
+
+ Native = 0x00000010,
+ Abstract = 0x00000020,
+ Static = 0x00000040,
+
+ FinalInTargetLang = 0x00000080,
+ FinalInCpp = 0x00000100,
+ ForceShellImplementation = 0x00000200,
+
+ GetterFunction = 0x00000400,
+ SetterFunction = 0x00000800,
+
+ FinalOverload = 0x00001000,
+ InterfaceFunction = 0x00002000,
+
+ PropertyReader = 0x00004000,
+ PropertyWriter = 0x00008000,
+ PropertyResetter = 0x00010000,
+
+ Fake = 0x00020000,
+
+ Invokable = 0x00040000,
+
+ Final = FinalInTargetLang | FinalInCpp
+ };
+ Q_DECLARE_FLAGS(Attributes, Attribute)
+ Q_FLAG(Attribute)
+
+ Attributes attributes() const
+ {
+ return m_attributes;
+ }
+
+ void setAttributes(Attributes attributes)
+ {
+ m_attributes = attributes;
+ }
+
+ Attributes originalAttributes() const
+ {
+ return m_originalAttributes;
+ }
+
+ void setOriginalAttributes(Attributes attributes)
+ {
+ m_originalAttributes = attributes;
+ }
+
+ Attributes visibility() const
+ {
+ return m_attributes & Visibility;
+ }
+
+ void setVisibility(Attributes visi)
+ {
+ m_attributes = (m_attributes & ~Visibility) | visi;
+ }
+
+ void operator+=(Attribute attribute)
+ {
+ m_attributes |= attribute;
+ }
+
+ void operator-=(Attribute attribute)
+ {
+ m_attributes &= ~attribute;
+ }
+
+ bool isNative() const
+ {
+ return m_attributes & Native;
+ }
+
+ bool isFinal() const
+ {
+ return (m_attributes & Final) == Final;
+ }
+
+ bool isFinalInTargetLang() const
+ {
+ return m_attributes & FinalInTargetLang;
+ }
+
+ bool isFinalInCpp() const
+ {
+ return m_attributes & FinalInCpp;
+ }
+
+ bool isAbstract() const
+ {
+ return m_attributes & Abstract;
+ }
+
+ bool isStatic() const
+ {
+ return m_attributes & Static;
+ }
+
+ bool isForcedShellImplementation() const
+ {
+ return m_attributes & ForceShellImplementation;
+ }
+
+ bool isInterfaceFunction() const
+ {
+ return m_attributes & InterfaceFunction;
+ }
+
+ bool isFinalOverload() const
+ {
+ return m_attributes & FinalOverload;
+ }
+
+ bool isInvokable() const
+ {
+ return m_attributes & Invokable;
+ }
+
+ bool isPropertyReader() const
+ {
+ return m_attributes & PropertyReader;
+ }
+
+ bool isPropertyWriter() const
+ {
+ return m_attributes & PropertyWriter;
+ }
+
+ bool isPropertyResetter() const
+ {
+ return m_attributes & PropertyResetter;
+ }
+
+ bool isPrivate() const
+ {
+ return m_attributes & Private;
+ }
+
+ bool isProtected() const
+ {
+ return m_attributes & Protected;
+ }
+
+ bool isPublic() const
+ {
+ return m_attributes & Public;
+ }
+
+ bool isFriendly() const
+ {
+ return m_attributes & Friendly;
+ }
+
+ bool wasPrivate() const
+ {
+ return m_originalAttributes & Private;
+ }
+
+ bool wasProtected() const
+ {
+ return m_originalAttributes & Protected;
+ }
+
+ bool wasPublic() const
+ {
+ return m_originalAttributes & Public;
+ }
+
+ bool wasFriendly() const
+ {
+ return m_originalAttributes & Friendly;
+ }
+
+ void setDocumentation(const Documentation& doc)
+ {
+ m_doc = doc;
+ }
+
+ Documentation documentation() const
+ {
+ return m_doc;
+ }
+
+private:
+ Attributes m_attributes;
+ Attributes m_originalAttributes;
+ Documentation m_doc;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaAttributes::Attributes)
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaAttributes *aa);
+#endif
+
+class AbstractMetaType
+{
+ Q_GADGET
+public:
+
+ enum TypeUsagePattern {
+ InvalidPattern,
+ PrimitivePattern,
+ FlagsPattern,
+ EnumPattern,
+ ValuePattern,
+ StringPattern,
+ CharPattern,
+ ObjectPattern,
+ QObjectPattern,
+ ValuePointerPattern,
+ NativePointerPattern,
+ ContainerPattern,
+ SmartPointerPattern,
+ VariantPattern,
+ VarargsPattern,
+ JObjectWrapperPattern,
+ ArrayPattern,
+ ThreadPattern
+ };
+ Q_ENUM(TypeUsagePattern)
+
+ AbstractMetaType();
+ ~AbstractMetaType();
+
+ QString package() const;
+ QString name() const;
+ QString fullName() const;
+
+ void setTypeUsagePattern(TypeUsagePattern pattern)
+ {
+ m_pattern = pattern;
+ }
+ TypeUsagePattern typeUsagePattern() const
+ {
+ return m_pattern;
+ }
+
+ // true when use pattern is container
+ bool hasInstantiations() const
+ {
+ return !m_instantiations.isEmpty();
+ }
+
+ void addInstantiation(AbstractMetaType* inst, bool owner = false)
+ {
+ if (owner)
+ m_children << inst;
+ m_instantiations << inst;
+ }
+
+ void setInstantiations(const AbstractMetaTypeList &insts, bool owner = false)
+ {
+ m_instantiations = insts;
+ if (owner) {
+ m_children.clear();
+ m_children = insts;
+ }
+ }
+
+ AbstractMetaTypeList instantiations() const
+ {
+ return m_instantiations;
+ }
+
+ void setInstantiationInCpp(bool incpp)
+ {
+ m_cppInstantiation = incpp;
+ }
+ bool hasInstantiationInCpp() const
+ {
+ return hasInstantiations() && m_cppInstantiation;
+ }
+
+ QString minimalSignature() const;
+
+ // true when the type is a QtJambiObject subclass
+ bool hasNativeId() const;
+
+ // returns true if the typs is used as a non complex primitive, no & or *'s
+ bool isPrimitive() const
+ {
+ return m_pattern == PrimitivePattern;
+ }
+
+ // returns true if the type is used as an enum
+ bool isEnum() const
+ {
+ return m_pattern == EnumPattern;
+ }
+
+ // returns true if the type is used as a QObject *
+ bool isQObject() const
+ {
+ return m_pattern == QObjectPattern;
+ }
+
+ // returns true if the type is used as an object, e.g. Xxx *
+ bool isObject() const
+ {
+ return m_pattern == ObjectPattern;
+ }
+
+ // returns true if the type is used as an array, e.g. Xxx[42]
+ bool isArray() const
+ {
+ return m_pattern == ArrayPattern;
+ }
+
+ // returns true if the type is used as a value type (X or const X &)
+ bool isValue() const
+ {
+ return m_pattern == ValuePattern;
+ }
+
+ bool isValuePointer() const
+ {
+ return m_pattern == ValuePointerPattern;
+ }
+
+ // returns true for more complex types...
+ bool isNativePointer() const
+ {
+ return m_pattern == NativePointerPattern;
+ }
+
+ // returns true if the type was originally a QString or const QString & or equivalent for QLatin1String
+ bool isTargetLangString() const
+ {
+ return m_pattern == StringPattern;
+ }
+
+ // returns true if the type was originally a QChar or const QChar &
+ bool isTargetLangChar() const
+ {
+ return m_pattern == CharPattern;
+ }
+
+ // return true if the type was originally a QVariant or const QVariant &
+ bool isVariant() const
+ {
+ return m_pattern == VariantPattern;
+ }
+
+ // return true if the type was originally a varargs
+ bool isVarargs() const
+ {
+ return m_pattern == VarargsPattern;
+ }
+
+ // return true if the type was originally a JObjectWrapper or const JObjectWrapper &
+ bool isJObjectWrapper() const
+ {
+ return m_pattern == JObjectWrapperPattern;
+ }
+
+ // returns true if the type was used as a container
+ bool isContainer() const
+ {
+ return m_pattern == ContainerPattern;
+ }
+
+ // returns true if the type was used as a smart pointer
+ bool isSmartPointer() const { return m_pattern == SmartPointerPattern; }
+
+ // returns true if the type was used as a flag
+ bool isFlags() const
+ {
+ return m_pattern == FlagsPattern;
+ }
+
+ // returns true if the type was used as a thread
+ bool isThread() const
+ {
+ return m_pattern == ThreadPattern;
+ }
+
+ bool isConstant() const
+ {
+ return m_constant;
+ }
+ void setConstant(bool constant)
+ {
+ m_constant = constant;
+ }
+
+ ReferenceType referenceType() const { return m_referenceType; }
+ void setReferenceType(ReferenceType ref) { m_referenceType = ref; }
+
+ /**
+ * Says if the type is to be implemented using target language
+ * equivalent of C++ enums, i.e. not plain ints.
+ * /return true if the type is to be implemented using target
+ * language enums
+ */
+ bool isTargetLangEnum() const;
+ bool isIntegerEnum() const
+ {
+ return isEnum() && !isTargetLangEnum();
+ }
+
+ /**
+ * Says if the type is to be implemented using target language
+ * equivalent of Qt's QFlags, i.e. not plain ints.
+ * /return true if the type is to be implemented using target
+ * language QFlags
+ */
+ bool isTargetLangFlags() const;
+ bool isIntegerFlags() const
+ {
+ return isFlags() && !isTargetLangFlags();
+ }
+
+ int actualIndirections() const
+ {
+ return m_indirections + (m_referenceType == LValueReference ? 1 : 0);
+ }
+ int indirections() const
+ {
+ return m_indirections;
+ }
+ void setIndirections(int indirections)
+ {
+ m_indirections = indirections;
+ }
+
+ void setArrayElementCount(int n)
+ {
+ m_arrayElementCount = n;
+ }
+ int arrayElementCount() const
+ {
+ return m_arrayElementCount;
+ }
+
+ const AbstractMetaType *arrayElementType() const
+ {
+ return m_arrayElementType;
+ }
+ void setArrayElementType(const AbstractMetaType *t)
+ {
+ m_arrayElementType = t;
+ }
+
+ QString cppSignature() const;
+
+ AbstractMetaType *copy() const;
+
+ const TypeEntry *typeEntry() const
+ {
+ return m_typeEntry;
+ }
+ void setTypeEntry(const TypeEntry *type)
+ {
+ m_typeEntry = type;
+ }
+
+ void setOriginalTypeDescription(const QString &otd)
+ {
+ m_originalTypeDescription = otd;
+ }
+ QString originalTypeDescription() const
+ {
+ return m_originalTypeDescription;
+ }
+
+ void setOriginalTemplateType(const AbstractMetaType *type)
+ {
+ m_originalTemplateType = type;
+ }
+ const AbstractMetaType *originalTemplateType() const
+ {
+ return m_originalTemplateType;
+ }
+
+ AbstractMetaType *getSmartPointerInnerType() const
+ {
+ Q_ASSERT(isSmartPointer());
+ AbstractMetaTypeList instantiations = this->instantiations();
+ Q_ASSERT(!instantiations.isEmpty());
+ AbstractMetaType *innerType = instantiations.at(0);
+ return innerType;
+ }
+
+ QString getSmartPointerInnerTypeName() const
+ {
+ Q_ASSERT(isSmartPointer());
+ AbstractMetaType *innerType = getSmartPointerInnerType();
+ Q_ASSERT(innerType);
+ return innerType->name();
+ }
+
+ /// Decides and sets the proper usage patter for the current meta type.
+ void decideUsagePattern();
+
+ bool hasTemplateChildren() const;
+
+private:
+ TypeUsagePattern determineUsagePattern() const;
+
+ const TypeEntry *m_typeEntry;
+ AbstractMetaTypeList m_instantiations;
+ QString m_package;
+ mutable QString m_name;
+ mutable QString m_cachedCppSignature;
+ QString m_originalTypeDescription;
+
+ int m_arrayElementCount;
+ const AbstractMetaType *m_arrayElementType;
+ const AbstractMetaType *m_originalTemplateType;
+
+ TypeUsagePattern m_pattern;
+ uint m_constant : 1;
+ uint m_cppInstantiation : 1;
+ int m_indirections : 4;
+ uint m_reserved : 26; // unused
+ ReferenceType m_referenceType;
+ AbstractMetaTypeList m_children;
+
+ Q_DISABLE_COPY(AbstractMetaType);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaType *at);
+#endif
+
+class AbstractMetaVariable
+{
+public:
+ AbstractMetaVariable() : m_type(0), m_hasName(false) {}
+ AbstractMetaVariable(const AbstractMetaVariable &other);
+
+ virtual ~AbstractMetaVariable()
+ {
+ delete m_type;
+ }
+
+ AbstractMetaType *type() const
+ {
+ return m_type;
+ }
+ void setType(AbstractMetaType *type)
+ {
+ Q_ASSERT(m_type == 0);
+ m_type = type;
+ }
+ void replaceType(AbstractMetaType *type)
+ {
+ if (m_type)
+ delete m_type;
+ m_type = type;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+ void setName(const QString &name, bool realName = true)
+ {
+ m_name = name;
+ m_hasName = realName;
+ }
+ bool hasName() const
+ {
+ return m_hasName;
+ }
+ QString originalName() const
+ {
+ return m_originalName;
+ }
+ void setOriginalName(const QString& name)
+ {
+ m_originalName = name;
+ }
+ void setDocumentation(const Documentation& doc)
+ {
+ m_doc = doc;
+ }
+ Documentation documentation() const
+ {
+ return m_doc;
+ }
+
+private:
+ QString m_originalName;
+ QString m_name;
+ AbstractMetaType *m_type;
+ bool m_hasName;
+
+ Documentation m_doc;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaVariable *av);
+#endif
+
+class AbstractMetaArgument : public AbstractMetaVariable
+{
+public:
+ AbstractMetaArgument() : m_argumentIndex(0) {};
+
+ QString defaultValueExpression() const
+ {
+ return m_expression;
+ }
+ void setDefaultValueExpression(const QString &expr)
+ {
+ m_expression = expr;
+ }
+
+ QString originalDefaultValueExpression() const
+ {
+ return m_originalExpression;
+ }
+ void setOriginalDefaultValueExpression(const QString &expr)
+ {
+ m_originalExpression = expr;
+ }
+
+ QString toString() const
+ {
+ return type()->name() + QLatin1Char(' ') + AbstractMetaVariable::name() +
+ (m_expression.isEmpty() ? QString() : QLatin1String(" = ") + m_expression);
+ }
+
+ int argumentIndex() const
+ {
+ return m_argumentIndex;
+ }
+ void setArgumentIndex(int argIndex)
+ {
+ m_argumentIndex = argIndex;
+ }
+
+ AbstractMetaArgument *copy() const;
+private:
+ QString m_expression;
+ QString m_originalExpression;
+ int m_argumentIndex;
+
+ friend class AbstractMetaClass;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaArgument *aa);
+#endif
+
+class AbstractMetaField : public AbstractMetaVariable, public AbstractMetaAttributes
+{
+public:
+ AbstractMetaField();
+ ~AbstractMetaField();
+
+ const AbstractMetaClass *enclosingClass() const
+ {
+ return m_class;
+ }
+ void setEnclosingClass(const AbstractMetaClass *cls)
+ {
+ m_class = cls;
+ }
+
+ const AbstractMetaFunction *getter() const;
+ const AbstractMetaFunction *setter() const;
+
+ FieldModificationList modifications() const;
+
+ bool isModifiedRemoved(int types = TypeSystem::All) const;
+
+ using AbstractMetaVariable::setDocumentation;
+ using AbstractMetaVariable::documentation;
+
+ AbstractMetaField *copy() const;
+
+private:
+ mutable AbstractMetaFunction *m_getter;
+ mutable AbstractMetaFunction *m_setter;
+ const AbstractMetaClass *m_class;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaField *af);
+#endif
+
+class AbstractMetaFunction : public AbstractMetaAttributes
+{
+ Q_GADGET
+public:
+ enum FunctionType {
+ ConstructorFunction,
+ CopyConstructorFunction,
+ MoveConstructorFunction,
+ AssignmentOperatorFunction,
+ MoveAssignmentOperatorFunction,
+ DestructorFunction,
+ NormalFunction,
+ SignalFunction,
+ EmptyFunction,
+ SlotFunction,
+ GlobalScopeFunction
+ };
+ Q_ENUM(FunctionType)
+
+ enum CompareResultFlag {
+ EqualName = 0x00000001,
+ EqualArguments = 0x00000002,
+ EqualAttributes = 0x00000004,
+ EqualImplementor = 0x00000008,
+ EqualReturnType = 0x00000010,
+ EqualDefaultValueOverload = 0x00000020,
+ EqualModifiedName = 0x00000040,
+
+ NameLessThan = 0x00001000,
+
+ PrettySimilar = EqualName | EqualArguments,
+ Equal = 0x0000001f,
+ NotEqual = 0x00001000
+ };
+ Q_DECLARE_FLAGS(CompareResult, CompareResultFlag)
+ Q_FLAG(CompareResultFlag)
+
+ AbstractMetaFunction()
+ : m_typeEntry(0),
+ m_functionType(NormalFunction),
+ m_type(0),
+ m_class(0),
+ m_implementingClass(0),
+ m_declaringClass(0),
+ m_propertySpec(0),
+ m_constant(false),
+ m_invalid(false),
+ m_reverse(false),
+ m_userAdded(false),
+ m_explicit(false),
+ m_pointerOperator(false),
+ m_isCallOperator(false)
+ {
+ }
+
+ ~AbstractMetaFunction();
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ void setName(const QString &name)
+ {
+ m_name = name;
+ }
+
+ QString originalName() const
+ {
+ return m_originalName.isEmpty() ? name() : m_originalName;
+ }
+
+ void setOriginalName(const QString &name)
+ {
+ m_originalName = name;
+ }
+
+ void setReverseOperator(bool reverse)
+ {
+ m_reverse = reverse;
+ }
+
+ bool isReverseOperator() const
+ {
+ return m_reverse;
+ }
+
+ /**
+ * Returns true if this is a operator and the "self" operand is a pointer.
+ * e.g. class Foo {}; operator+(SomeEnum, Foo*);
+ */
+ bool isPointerOperator() const
+ {
+ return m_pointerOperator;
+ }
+
+ void setPointerOperator(bool value)
+ {
+ m_pointerOperator = value;
+ }
+
+ void setExplicit(bool isExplicit)
+ {
+ m_explicit = isExplicit;
+ }
+ /**
+ * Says if the function (a constructor) was declared as explicit in C++.
+ * \return true if the function was declared as explicit in C++
+ */
+ bool isExplicit() const
+ {
+ return m_explicit;
+ }
+
+ static bool isConversionOperator(QString funcName);
+ bool isConversionOperator() const
+ {
+ return isConversionOperator(originalName());
+ }
+
+ static bool isOperatorOverload(QString funcName);
+ bool isOperatorOverload() const
+ {
+ return isOperatorOverload(originalName());
+ }
+ bool isCastOperator() const;
+
+ bool isArithmeticOperator() const;
+ bool isBitwiseOperator() const;
+ bool isComparisonOperator() const;
+ bool isLogicalOperator() const;
+ bool isSubscriptOperator() const;
+ bool isAssignmentOperator() const; // Assignment or move assignment
+ bool isOtherOperator() const;
+
+ /**
+ * Informs the arity of the operator or -1 if the function is not
+ * an operator overload.
+ * /return the arity of the operator or -1
+ */
+ int arityOfOperator() const;
+ bool isUnaryOperator() const { return arityOfOperator() == 1; }
+ bool isBinaryOperator() const { return arityOfOperator() == 2; }
+ bool isInplaceOperator() const;
+
+ // TODO: ths function *should* know if it is virtual
+ // instead of asking to your implementing class.
+ bool isVirtual() const;
+ bool isThread() const;
+ bool allowThread() const;
+ QString modifiedName() const;
+
+ QString minimalSignature() const;
+ QStringList possibleIntrospectionCompatibleSignatures() const;
+
+ QString marshalledName() const;
+
+ // true if one or more of the arguments are of QtJambiObject subclasses
+ bool argumentsHaveNativeId() const
+ {
+ for (const AbstractMetaArgument *arg : m_arguments) {
+ if (arg->type()->hasNativeId())
+ return true;
+ }
+
+ return false;
+ }
+
+ bool isModifiedRemoved(int types = TypeSystem::All) const;
+
+ AbstractMetaType *type() const
+ {
+ return m_type;
+ }
+ void setType(AbstractMetaType *type)
+ {
+ Q_ASSERT(m_type == 0);
+ m_type = type;
+ }
+
+ void replaceType(AbstractMetaType *type)
+ {
+ if (m_type)
+ delete m_type;
+ m_type = type;
+ }
+
+ // The class that has this function as a member.
+ const AbstractMetaClass *ownerClass() const
+ {
+ return m_class;
+ }
+ void setOwnerClass(const AbstractMetaClass *cls)
+ {
+ m_class = cls;
+ }
+
+ // The first class in a hierarchy that declares the function
+ const AbstractMetaClass *declaringClass() const
+ {
+ return m_declaringClass;
+ }
+ void setDeclaringClass(const AbstractMetaClass *cls)
+ {
+ m_declaringClass = cls;
+ }
+
+ // The class that actually implements this function
+ const AbstractMetaClass *implementingClass() const
+ {
+ return m_implementingClass;
+ }
+ void setImplementingClass(const AbstractMetaClass *cls)
+ {
+ m_implementingClass = cls;
+ }
+
+ bool needsCallThrough() const;
+
+ AbstractMetaArgumentList arguments() const
+ {
+ return m_arguments;
+ }
+ void setArguments(const AbstractMetaArgumentList &arguments)
+ {
+ m_arguments = arguments;
+ }
+ void addArgument(AbstractMetaArgument *argument)
+ {
+ m_arguments << argument;
+ }
+ int actualMinimumArgumentCount() const;
+
+ void setInvalid(bool on)
+ {
+ m_invalid = on;
+ }
+ bool isInvalid() const
+ {
+ return m_invalid;
+ }
+ bool isDeprecated() const;
+ bool isDestructor() const
+ {
+ return functionType() == DestructorFunction;
+ }
+ bool isConstructor() const
+ {
+ return m_functionType == ConstructorFunction || m_functionType == CopyConstructorFunction
+ || m_functionType == MoveConstructorFunction;
+ }
+ bool isNormal() const
+ {
+ return functionType() == NormalFunction || isSlot() || isInGlobalScope();
+ }
+ bool isInGlobalScope() const
+ {
+ return functionType() == GlobalScopeFunction;
+ }
+ bool isSignal() const
+ {
+ return functionType() == SignalFunction;
+ }
+ bool isSlot() const
+ {
+ return functionType() == SlotFunction;
+ }
+ bool isEmptyFunction() const
+ {
+ return functionType() == EmptyFunction;
+ }
+ FunctionType functionType() const
+ {
+ return m_functionType;
+ }
+ void setFunctionType(FunctionType type)
+ {
+ m_functionType = type;
+ }
+
+ bool usesRValueReferences() const;
+ QStringList introspectionCompatibleSignatures(const QStringList &resolvedArguments = QStringList()) const;
+ QString signature() const;
+ QString targetLangSignature(bool minimal = false) const;
+ bool shouldReturnThisObject() const
+ {
+ return QLatin1String("this") == argumentReplaced(0);
+ }
+ bool shouldIgnoreReturnValue() const
+ {
+ return QLatin1String("void") == argumentReplaced(0);
+ }
+
+ bool isConstant() const
+ {
+ return m_constant;
+ }
+ void setConstant(bool constant)
+ {
+ m_constant = constant;
+ }
+
+ /// Returns true if the AbstractMetaFunction was added by the user via the type system description.
+ bool isUserAdded() const
+ {
+ return m_userAdded;
+ }
+ void setUserAdded(bool userAdded)
+ {
+ m_userAdded = userAdded;
+ }
+
+ QString toString() const
+ {
+ return m_name;
+ }
+
+ CompareResult compareTo(const AbstractMetaFunction *other) const;
+
+ bool operator <(const AbstractMetaFunction &a) const;
+
+ AbstractMetaFunction *copy() const;
+
+ QString replacedDefaultExpression(const AbstractMetaClass *cls, int idx) const;
+ bool removedDefaultExpression(const AbstractMetaClass *cls, int idx) const;
+ QString conversionRule(TypeSystem::Language language, int idx) const;
+ QVector<ReferenceCount> referenceCounts(const AbstractMetaClass *cls, int idx = -2) const;
+ ArgumentOwner argumentOwner(const AbstractMetaClass *cls, int idx) const;
+
+ bool nullPointersDisabled(const AbstractMetaClass *cls = 0, int argument_idx = 0) const;
+ QString nullPointerDefaultValue(const AbstractMetaClass *cls = 0, int argument_idx = 0) const;
+
+ bool resetObjectAfterUse(int argument_idx) const;
+
+ // Returns whether garbage collection is disabled for the argument in any context
+ bool disabledGarbageCollection(const AbstractMetaClass *cls, int key) const;
+
+ // Returns the ownership rules for the given argument in the given context
+ TypeSystem::Ownership ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int idx) const;
+
+ bool isVirtualSlot() const;
+
+ QString typeReplaced(int argument_index) const;
+ bool isRemovedFromAllLanguages(const AbstractMetaClass *) const;
+ bool isRemovedFrom(const AbstractMetaClass *, TypeSystem::Language language) const;
+ bool argumentRemoved(int) const;
+
+ QString argumentReplaced(int key) const;
+ bool needsSuppressUncheckedWarning() const;
+
+ bool hasModifications(const AbstractMetaClass *implementor) const;
+ /**
+ * Verifies if any modification to the function is an inject code.
+ * \return true if there is inject code modifications to the function.
+ */
+ bool hasInjectedCode() const;
+ /**
+ * Returns a list of code snips for this function.
+ * The code snips can be filtered by position and language.
+ * \return list of code snips
+ */
+ CodeSnipList injectedCodeSnips(TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny,
+ TypeSystem::Language language = TypeSystem::All) const;
+
+ /**
+ * Verifies if any modification to the function alters/removes its
+ * arguments types or default values.
+ * \return true if there is some modification to function signature
+ */
+ bool hasSignatureModifications() const;
+ FunctionModificationList modifications(const AbstractMetaClass* implementor = 0) const;
+
+ /**
+ * Return the argument name if there is a modification the renamed value will be returned
+ */
+ QString argumentName(int index, bool create = true, const AbstractMetaClass *cl = 0) const;
+
+ void setPropertySpec(QPropertySpec *spec)
+ {
+ m_propertySpec = spec;
+ }
+
+ QPropertySpec *propertySpec() const
+ {
+ return m_propertySpec;
+ }
+
+ FunctionTypeEntry* typeEntry() const
+ {
+ return m_typeEntry;
+ }
+
+ void setTypeEntry(FunctionTypeEntry* typeEntry)
+ {
+ m_typeEntry = typeEntry;
+ }
+
+ bool isCallOperator() const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebugVerbose(QDebug &d) const;
+#endif
+
+private:
+ QString m_name;
+ QString m_originalName;
+ mutable QString m_cachedMinimalSignature;
+ mutable QString m_cachedSignature;
+ mutable QString m_cachedModifiedName;
+
+ FunctionTypeEntry* m_typeEntry;
+ FunctionType m_functionType;
+ AbstractMetaType *m_type;
+ const AbstractMetaClass *m_class;
+ const AbstractMetaClass *m_implementingClass;
+ const AbstractMetaClass *m_declaringClass;
+ QPropertySpec *m_propertySpec;
+ AbstractMetaArgumentList m_arguments;
+ uint m_constant : 1;
+ uint m_invalid : 1;
+ uint m_reverse : 1;
+ uint m_userAdded : 1;
+ uint m_explicit : 1;
+ uint m_pointerOperator : 1;
+ uint m_isCallOperator : 1;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaFunction::CompareResult)
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaFunction *af);
+#endif
+
+class AbstractMetaEnumValue
+{
+public:
+ AbstractMetaEnumValue()
+ : m_valueSet(false), m_value(0)
+ {
+ }
+
+ int value() const
+ {
+ return m_value;
+ }
+
+ void setValue(int value)
+ {
+ m_valueSet = true;
+ m_value = value;
+ }
+
+ QString stringValue() const
+ {
+ return m_stringValue;
+ }
+
+ void setStringValue(const QString &v)
+ {
+ m_stringValue = v;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ void setName(const QString &name)
+ {
+ m_name = name;
+ }
+
+ bool isValueSet() const
+ {
+ return m_valueSet;
+ }
+
+ void setDocumentation(const Documentation& doc)
+ {
+ m_doc = doc;
+ }
+
+ Documentation documentation() const
+ {
+ return m_doc;
+ }
+
+private:
+ QString m_name;
+ QString m_stringValue;
+
+ bool m_valueSet;
+ int m_value;
+
+ Documentation m_doc;
+};
+
+class AbstractMetaEnum : public AbstractMetaAttributes
+{
+public:
+ AbstractMetaEnum() : m_typeEntry(0), m_class(0), m_hasQenumsDeclaration(false) {}
+ ~AbstractMetaEnum()
+ {
+ qDeleteAll(m_enumValues);
+ }
+
+ AbstractMetaEnumValueList values() const
+ {
+ return m_enumValues;
+ }
+
+ void addEnumValue(AbstractMetaEnumValue *enumValue)
+ {
+ m_enumValues << enumValue;
+ }
+
+ QString name() const;
+
+ QString qualifier() const;
+
+ QString package() const;
+
+ QString fullName() const
+ {
+ return package() + QLatin1Char('.') + qualifier() + QLatin1Char('.') + name();
+ }
+
+ // Has the enum been declared inside a Q_ENUMS() macro in its enclosing class?
+ void setHasQEnumsDeclaration(bool on)
+ {
+ m_hasQenumsDeclaration = on;
+ }
+
+ bool hasQEnumsDeclaration() const
+ {
+ return m_hasQenumsDeclaration;
+ }
+
+ EnumTypeEntry *typeEntry() const
+ {
+ return m_typeEntry;
+ }
+
+ void setTypeEntry(EnumTypeEntry *entry)
+ {
+ m_typeEntry = entry;
+ }
+
+ AbstractMetaClass *enclosingClass() const
+ {
+ return m_class;
+ }
+
+ void setEnclosingClass(AbstractMetaClass *c)
+ {
+ m_class = c;
+ }
+
+ bool isAnonymous() const;
+
+private:
+ AbstractMetaEnumValueList m_enumValues;
+ EnumTypeEntry *m_typeEntry;
+ AbstractMetaClass *m_class;
+
+ uint m_hasQenumsDeclaration : 1;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AbstractMetaEnum *ae);
+#endif
+
+class AbstractMetaClass : public AbstractMetaAttributes
+{
+ Q_GADGET
+public:
+ enum FunctionQueryOption {
+ Constructors = 0x0000001, // Only constructors
+ //Destructors = 0x0000002, // Only destructors. Not included in class.
+ VirtualFunctions = 0x0000004, // Only virtual functions (virtual in both TargetLang and C++)
+ FinalInTargetLangFunctions = 0x0000008, // Only functions that are non-virtual in TargetLang
+ FinalInCppFunctions = 0x0000010, // Only functions that are non-virtual in C++
+ ClassImplements = 0x0000020, // Only functions implemented by the current class
+ Inconsistent = 0x0000040, // Only inconsistent functions (inconsistent virtualness in TargetLang/C++)
+ StaticFunctions = 0x0000080, // Only static functions
+ Signals = 0x0000100, // Only signals
+ NormalFunctions = 0x0000200, // Only functions that aren't signals
+ Visible = 0x0000400, // Only public and protected functions
+ ForcedShellFunctions = 0x0000800, // Only functions that are overridden to be implemented in the shell class
+ WasPublic = 0x0001000, // Only functions that were originally public
+ WasProtected = 0x0002000, // Only functions that were originally protected
+ NonStaticFunctions = 0x0004000, // No static functions
+ Empty = 0x0008000, // Empty overrides of abstract functions
+ Invisible = 0x0010000, // Only private functions
+ VirtualInCppFunctions = 0x0020000, // Only functions that are virtual in C++
+ NonEmptyFunctions = 0x0040000, // Only functions with target language API implementations
+ VirtualInTargetLangFunctions = 0x0080000, // Only functions which are virtual in TargetLang
+ AbstractFunctions = 0x0100000, // Only abstract functions
+ WasVisible = 0x0200000, // Only functions that were public or protected in the original code
+ NotRemovedFromTargetLang = 0x0400000, // Only functions that have not been removed from TargetLang
+ NotRemovedFromShell = 0x0800000, // Only functions that have not been removed from the shell class
+ VirtualSlots = 0x1000000, // Only functions that are set as virtual slots in the type system
+ OperatorOverloads = 0x2000000 // Only functions that are operator overloads
+ };
+ Q_DECLARE_FLAGS(FunctionQueryOptions, FunctionQueryOption)
+ Q_FLAG(FunctionQueryOption)
+
+ enum OperatorQueryOption {
+ ArithmeticOp = 0x01, // Arithmetic: +, -, *, /, %, +=, -=, *=, /=, %=, ++, --, unary+, unary-
+ BitwiseOp = 0x02, // Bitwise: <<, <<=, >>, >>=, ~, &, &=, |, |=, ^, ^=
+ ComparisonOp = 0x04, // Comparison: <, <=, >, >=, !=, ==
+ LogicalOp = 0x08, // Logical: !, &&, ||
+ ConversionOp = 0x10, // Conversion: operator [const] TYPE()
+ SubscriptionOp = 0x20, // Subscription: []
+ AssignmentOp = 0x40, // Assignment: =
+ OtherOp = 0x80, // The remaining operators: call(), etc
+ AllOperators = ArithmeticOp | BitwiseOp | ComparisonOp
+ | LogicalOp | ConversionOp | SubscriptionOp
+ | AssignmentOp | OtherOp
+ };
+ Q_DECLARE_FLAGS(OperatorQueryOptions, OperatorQueryOption)
+ Q_FLAG(OperatorQueryOption)
+
+ AbstractMetaClass()
+ : m_hasVirtuals(false),
+ m_isPolymorphic(false),
+ m_hasNonpublic(false),
+ m_hasVirtualSlots(false),
+ m_hasNonPrivateConstructor(false),
+ m_functionsFixed(false),
+ m_hasPrivateDestructor(false),
+ m_hasProtectedDestructor(false),
+ m_hasVirtualDestructor(false),
+ m_forceShellClass(false),
+ m_hasHashFunction(false),
+ m_hasEqualsOperator(false),
+ m_hasCloneOperator(false),
+ m_isTypeDef(false),
+ m_hasToStringCapability(false),
+ m_enclosingClass(0),
+ m_baseClass(0),
+ m_templateBaseClass(0),
+ m_extractedInterface(0),
+ m_typeEntry(0),
+ m_stream(false)
+ {
+ }
+
+ virtual ~AbstractMetaClass();
+
+ AbstractMetaClass *extractInterface();
+ void fixFunctions();
+
+ AbstractMetaFunctionList functions() const
+ {
+ return m_functions;
+ }
+
+ void setFunctions(const AbstractMetaFunctionList &functions);
+ void addFunction(AbstractMetaFunction *function);
+ bool hasFunction(const AbstractMetaFunction *f) const;
+ bool hasFunction(const QString &str) const;
+ const AbstractMetaFunction* findFunction(const QString& functionName) const;
+ bool hasSignal(const AbstractMetaFunction *f) const;
+
+ bool hasConstructors() const;
+ bool hasCopyConstructor() const;
+ bool hasPrivateCopyConstructor() const;
+
+ void addDefaultConstructor();
+ void addDefaultCopyConstructor(bool isPrivate = false);
+
+ bool hasNonPrivateConstructor() const
+ {
+ return m_hasNonPrivateConstructor;
+ }
+
+ void setHasNonPrivateConstructor(bool value)
+ {
+ m_hasNonPrivateConstructor = value;
+ }
+
+ bool hasPrivateDestructor() const
+ {
+ return m_hasPrivateDestructor;
+ }
+
+ void setHasPrivateDestructor(bool value)
+ {
+ m_hasPrivateDestructor = value;
+ }
+
+ bool hasProtectedDestructor() const
+ {
+ return m_hasProtectedDestructor;
+ }
+
+ void setHasProtectedDestructor(bool value)
+ {
+ m_hasProtectedDestructor = value;
+ }
+
+ bool hasVirtualDestructor() const
+ {
+ return m_hasVirtualDestructor;
+ }
+
+ void setHasVirtualDestructor(bool value)
+ {
+ m_hasVirtualDestructor = value;
+ }
+
+ AbstractMetaFunctionList queryFunctionsByName(const QString &name) const;
+ AbstractMetaFunctionList queryFunctions(FunctionQueryOptions query) const;
+ AbstractMetaFunctionList functionsInTargetLang() const;
+ AbstractMetaFunctionList functionsInShellClass() const;
+ inline AbstractMetaFunctionList cppSignalFunctions() const;
+ AbstractMetaFunctionList publicOverrideFunctions() const;
+ AbstractMetaFunctionList virtualOverrideFunctions() const;
+ AbstractMetaFunctionList virtualFunctions() const;
+ AbstractMetaFunctionList implicitConversions() const;
+
+ /**
+ * Retrieves all class' operator overloads that meet
+ * query criteria defined with the OperatorQueryOption
+ * enum.
+ * /param query composition of OperatorQueryOption enum values
+ * /return list of operator overload methods that meet the
+ * query criteria
+ */
+ AbstractMetaFunctionList operatorOverloads(OperatorQueryOptions query = AllOperators) const;
+
+ bool hasOperatorOverload() const;
+ bool hasArithmeticOperatorOverload() const;
+ bool hasBitwiseOperatorOverload() const;
+ bool hasComparisonOperatorOverload() const;
+ bool hasLogicalOperatorOverload() const;
+ bool hasSubscriptOperatorOverload() const;
+ bool hasAssignmentOperatorOverload() const;
+ bool hasConversionOperatorOverload() const;
+
+ AbstractMetaFieldList fields() const
+ {
+ return m_fields;
+ }
+
+ void setFields(const AbstractMetaFieldList &fields)
+ {
+ m_fields = fields;
+ }
+
+ void addField(AbstractMetaField *field)
+ {
+ m_fields << field;
+ }
+
+ AbstractMetaEnumList enums() const
+ {
+ return m_enums;
+ }
+ void setEnums(const AbstractMetaEnumList &enums)
+ {
+ m_enums = enums;
+ }
+
+ void addEnum(AbstractMetaEnum *e)
+ {
+ m_enums << e;
+ }
+
+ AbstractMetaEnum *findEnum(const QString &enumName);
+ AbstractMetaEnum *findEnumForValue(const QString &enumName);
+ AbstractMetaEnumValue *findEnumValue(const QString &enumName, AbstractMetaEnum *meta_enum);
+
+ AbstractMetaClassList interfaces() const
+ {
+ return m_interfaces;
+ }
+ void addInterface(AbstractMetaClass *interface);
+ void setInterfaces(const AbstractMetaClassList &interface);
+
+ QString fullName() const
+ {
+ return package() + QLatin1Char('.') + name();
+ }
+
+ /**
+ * Retrieves the class name without any namespace/scope information.
+ * /return the class name without scope information
+ */
+ QString name() const;
+
+ QString baseClassName() const
+ {
+ return m_baseClass ? m_baseClass->name() : QString();
+ }
+
+ AbstractMetaClass *baseClass() const
+ {
+ return m_baseClass;
+ }
+
+ void setBaseClass(AbstractMetaClass *base_class);
+
+ const AbstractMetaClass *enclosingClass() const
+ {
+ return m_enclosingClass;
+ }
+
+ void setEnclosingClass(AbstractMetaClass *cl)
+ {
+ m_enclosingClass = cl;
+ }
+
+ const AbstractMetaClassList& innerClasses() const
+ {
+ return m_innerClasses;
+ }
+
+ void addInnerClass(AbstractMetaClass* cl)
+ {
+ m_innerClasses << cl;
+ }
+
+ void setInnerClasses(AbstractMetaClassList innerClasses)
+ {
+ m_innerClasses = innerClasses;
+ }
+
+ QString package() const;
+
+ bool isInterface() const;
+
+ bool isNamespace() const;
+
+ bool isQObject() const;
+
+ bool isQtNamespace() const
+ {
+ return isNamespace() && name() == QLatin1String("Qt");
+ }
+
+ QString qualifiedCppName() const;
+
+ bool hasSignals() const;
+ bool inheritsFrom(const AbstractMetaClass *other) const;
+
+ void setForceShellClass(bool on)
+ {
+ m_forceShellClass = on;
+ }
+
+ bool generateShellClass() const;
+
+ bool hasVirtualSlots() const
+ {
+ return m_hasVirtualSlots;
+ }
+
+ /**
+ * Says if a class has any virtual functions of its own.
+ * \return true if the class implements any virtual methods
+ */
+ bool hasVirtualFunctions() const
+ {
+ return !isFinal() && m_hasVirtuals;
+ }
+ /**
+ * Says if the class that declares or inherits a virtual function.
+ * \return true if the class implements or inherits any virtual methods
+ */
+ bool isPolymorphic() const
+ {
+ return m_isPolymorphic;
+ }
+
+ /**
+ * Tells if this class has one or more functions that are protected.
+ * \return true if the class has protected functions.
+ */
+ bool hasProtectedFunctions() const;
+
+ /**
+ * Tells if this class has one or more fields (member variables) that are protected.
+ * \return true if the class has protected fields.
+ */
+ bool hasProtectedFields() const;
+
+ /**
+ * Tells if this class has one or more members (functions or fields) that are protected.
+ * \return true if the class has protected members.
+ */
+ bool hasProtectedMembers() const;
+
+
+ QVector<TypeEntry *> templateArguments() const
+ {
+ return m_templateArgs;
+ }
+
+ void setTemplateArguments(const QVector<TypeEntry *> &args)
+ {
+ m_templateArgs = args;
+ }
+
+ bool hasFieldAccessors() const;
+
+ // only valid during metabuilder's run
+ QStringList baseClassNames() const
+ {
+ return m_baseClassNames;
+ }
+
+ void setBaseClassNames(const QStringList &names)
+ {
+ m_baseClassNames = names;
+ }
+
+ const ComplexTypeEntry *typeEntry() const
+ {
+ return m_typeEntry;
+ }
+
+ ComplexTypeEntry *typeEntry()
+ {
+ return m_typeEntry;
+ }
+
+ void setTypeEntry(ComplexTypeEntry *type)
+ {
+ m_typeEntry = type;
+ }
+
+ void setHasHashFunction(bool on)
+ {
+ m_hasHashFunction = on;
+ }
+
+ bool hasHashFunction() const
+ {
+ return m_hasHashFunction;
+ }
+ virtual bool hasDefaultToStringFunction() const;
+
+ void setHasEqualsOperator(bool on)
+ {
+ m_hasEqualsOperator = on;
+ }
+
+ bool hasEqualsOperator() const
+ {
+ return m_hasEqualsOperator;
+ }
+
+ void setHasCloneOperator(bool on)
+ {
+ m_hasCloneOperator = on;
+ }
+
+ bool hasCloneOperator() const
+ {
+ return m_hasCloneOperator;
+ }
+
+ void addPropertySpec(QPropertySpec *spec)
+ {
+ m_propertySpecs << spec;
+ }
+
+ QVector<QPropertySpec *> propertySpecs() const
+ {
+ return m_propertySpecs;
+ }
+
+ QPropertySpec *propertySpecForRead(const QString &name) const;
+ QPropertySpec *propertySpecForWrite(const QString &name) const;
+ QPropertySpec *propertySpecForReset(const QString &name) const;
+
+ /// Returns a list of conversion operators for this class. The conversion operators are defined in other classes of the same module.
+ AbstractMetaFunctionList externalConversionOperators() const
+ {
+ return m_externalConversionOperators;
+ }
+ /// Adds a converter operator for this class.
+ void addExternalConversionOperator(AbstractMetaFunction* conversionOp)
+ {
+ if (!m_externalConversionOperators.contains(conversionOp))
+ m_externalConversionOperators.append(conversionOp);
+ }
+ /// Returns true if this class has any converter operators defined elsewhere.
+ bool hasExternalConversionOperators() const
+ {
+ return !m_externalConversionOperators.isEmpty();
+ }
+
+ void sortFunctions();
+
+ const AbstractMetaClass *templateBaseClass() const
+ {
+ return m_templateBaseClass;
+ }
+
+ void setTemplateBaseClass(const AbstractMetaClass *cls)
+ {
+ m_templateBaseClass = cls;
+ }
+
+ bool hasTemplateBaseClassInstantiations() const;
+ AbstractMetaTypeList templateBaseClassInstantiations() const;
+ void setTemplateBaseClassInstantiations(AbstractMetaTypeList& instantiations);
+
+ void setTypeDef(bool typeDef) { m_isTypeDef = typeDef; }
+ bool isTypeDef() const { return m_isTypeDef; }
+
+ void setStream(bool stream)
+ {
+ m_stream = stream;
+ }
+
+ bool isStream() const
+ {
+ return m_stream;
+ }
+
+ void setToStringCapability(bool value)
+ {
+ m_hasToStringCapability = value;
+ }
+
+ bool hasToStringCapability() const
+ {
+ return m_hasToStringCapability;
+ }
+
+ static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
+ const QString &name);
+ static AbstractMetaClass *findClass(const AbstractMetaClassList &classes,
+ const TypeEntry* typeEntry);
+ static AbstractMetaEnumValue *findEnumValue(const AbstractMetaClassList &classes,
+ const QString &string);
+ static AbstractMetaEnum *findEnum(const AbstractMetaClassList &classes,
+ const EnumTypeEntry *entry);
+
+private:
+#ifndef QT_NO_DEBUG_STREAM
+ friend QDebug operator<<(QDebug d, const AbstractMetaClass *ac);
+#endif
+ uint m_hasVirtuals : 1;
+ uint m_isPolymorphic : 1;
+ uint m_hasNonpublic : 1;
+ uint m_hasVirtualSlots : 1;
+ uint m_hasNonPrivateConstructor : 1;
+ uint m_functionsFixed : 1;
+ uint m_hasPrivateDestructor : 1;
+ uint m_hasProtectedDestructor : 1;
+ uint m_hasVirtualDestructor : 1;
+ uint m_forceShellClass : 1;
+ uint m_hasHashFunction : 1;
+ uint m_hasEqualsOperator : 1;
+ uint m_hasCloneOperator : 1;
+ uint m_isTypeDef : 1;
+ uint m_hasToStringCapability : 1;
+
+ const AbstractMetaClass *m_enclosingClass;
+ AbstractMetaClass *m_baseClass;
+ const AbstractMetaClass *m_templateBaseClass;
+ AbstractMetaFunctionList m_functions;
+ AbstractMetaFieldList m_fields;
+ AbstractMetaEnumList m_enums;
+ AbstractMetaClassList m_interfaces;
+ AbstractMetaClass *m_extractedInterface;
+ QVector<QPropertySpec *> m_propertySpecs;
+ AbstractMetaClassList m_innerClasses;
+
+ AbstractMetaFunctionList m_externalConversionOperators;
+
+ QStringList m_baseClassNames;
+ QVector<TypeEntry *> m_templateArgs;
+ ComplexTypeEntry *m_typeEntry;
+// FunctionModelItem m_qDebugStreamFunction;
+
+ bool m_stream;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::FunctionQueryOptions)
+Q_DECLARE_OPERATORS_FOR_FLAGS(AbstractMetaClass::OperatorQueryOptions)
+
+class QPropertySpec
+{
+public:
+ QPropertySpec(const TypeEntry *type)
+ : m_type(type),
+ m_index(-1)
+ {}
+
+ const TypeEntry *type() const
+ {
+ return m_type;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ void setName(const QString &name)
+ {
+ m_name = name;
+ }
+
+ QString read() const
+ {
+ return m_read;
+ }
+
+ void setRead(const QString &read)
+ {
+ m_read = read;
+ }
+
+ QString write() const
+ {
+ return m_write;
+ }
+
+ void setWrite(const QString &write)
+ {
+ m_write = write;
+ }
+
+ QString designable() const
+ {
+ return m_designable;
+ }
+
+ void setDesignable(const QString &designable)
+ {
+ m_designable = designable;
+ }
+
+ QString reset() const
+ {
+ return m_reset;
+ }
+
+ void setReset(const QString &reset)
+ {
+ m_reset = reset;
+ }
+
+ int index() const
+ {
+ return m_index;
+ }
+
+ void setIndex(int index)
+ {
+ m_index = index;
+ }
+
+private:
+ QString m_name;
+ QString m_read;
+ QString m_write;
+ QString m_designable;
+ QString m_reset;
+ const TypeEntry *m_type;
+ int m_index;
+};
+
+inline AbstractMetaFunctionList AbstractMetaClass::cppSignalFunctions() const
+{
+ return queryFunctions(Signals
+ | Visible
+ | NotRemovedFromTargetLang);
+}
+
+#endif // ABSTRACTMETALANG_H
diff --git a/sources/shiboken2/ApiExtractor/abstractmetalang_typedefs.h b/sources/shiboken2/ApiExtractor/abstractmetalang_typedefs.h
new file mode 100644
index 000000000..da8369895
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/abstractmetalang_typedefs.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ABSTRACTMETALANG_TYPEDEFS_H
+#define ABSTRACTMETALANG_TYPEDEFS_H
+
+#include <QtCore/QVector>
+
+class AbstractMetaClass;
+class AbstractMetaField;
+class AbstractMetaArgument;
+class AbstractMetaEnum;
+class AbstractMetaEnumValue;
+class AbstractMetaFunction;
+class AbstractMetaType;
+
+typedef QVector<AbstractMetaArgument *> AbstractMetaArgumentList;
+typedef QVector<AbstractMetaClass *> AbstractMetaClassList;
+typedef QVector<AbstractMetaEnum *> AbstractMetaEnumList;
+typedef QVector<AbstractMetaEnumValue *> AbstractMetaEnumValueList;
+typedef QVector<AbstractMetaField *> AbstractMetaFieldList;
+typedef QVector<AbstractMetaFunction *> AbstractMetaFunctionList;
+typedef QVector<AbstractMetaType *> AbstractMetaTypeList;
+
+#endif // ABSTRACTMETALANG_TYPEDEFS_H
diff --git a/sources/shiboken2/ApiExtractor/apiextractor.cpp b/sources/shiboken2/ApiExtractor/apiextractor.cpp
new file mode 100644
index 000000000..abb7c08b9
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp
@@ -0,0 +1,317 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "apiextractor.h"
+#include "abstractmetalang.h"
+
+#include <QDir>
+#include <QDebug>
+#include <QTemporaryFile>
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+
+#include "reporthandler.h"
+#include "typesystem.h"
+#include "fileout.h"
+#include "abstractmetabuilder.h"
+#include "typedatabase.h"
+#include "typesystem.h"
+
+static bool appendFile(const QString& sourceFileName, QFile& targetFile)
+{
+ QFile sourceFile(sourceFileName);
+ if (!sourceFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ std::cerr << "Cannot open " << qPrintable(QDir::toNativeSeparators(sourceFileName))
+ << ": " << qPrintable(sourceFile.errorString()) << '\n';
+ return false;
+ }
+ targetFile.write(sourceFile.readAll());
+ return true;
+}
+
+ApiExtractor::ApiExtractor() : m_builder(0)
+{
+ // Environment TYPESYSTEMPATH
+ QString envTypesystemPaths = QFile::decodeName(getenv("TYPESYSTEMPATH"));
+ if (!envTypesystemPaths.isEmpty())
+ TypeDatabase::instance()->addTypesystemPath(envTypesystemPaths);
+}
+
+ApiExtractor::~ApiExtractor()
+{
+ delete m_builder;
+}
+
+void ApiExtractor::addTypesystemSearchPath (const QString& path)
+{
+ TypeDatabase::instance()->addTypesystemPath(path);
+}
+
+void ApiExtractor::addTypesystemSearchPath(const QStringList& paths)
+{
+ for (const QString &path : paths)
+ addTypesystemSearchPath(path);
+}
+
+void ApiExtractor::addIncludePath(const HeaderPath& path)
+{
+ m_includePaths << path;
+}
+
+void ApiExtractor::addIncludePath(const HeaderPaths& paths)
+{
+ m_includePaths << paths;
+}
+
+void ApiExtractor::setLogDirectory(const QString& logDir)
+{
+ m_logDirectory = logDir;
+}
+
+void ApiExtractor::setCppFileName(const QString& cppFileName)
+{
+ m_cppFileName = cppFileName;
+}
+
+void ApiExtractor::setTypeSystem(const QString& typeSystemFileName)
+{
+ m_typeSystemFileName = typeSystemFileName;
+}
+
+void ApiExtractor::setDebugLevel(ReportHandler::DebugLevel debugLevel)
+{
+ ReportHandler::setDebugLevel(debugLevel);
+}
+
+void ApiExtractor::setSuppressWarnings ( bool value )
+{
+ TypeDatabase::instance()->setSuppressWarnings(value);
+}
+
+void ApiExtractor::setSilent ( bool value )
+{
+ ReportHandler::setSilent(value);
+}
+
+bool ApiExtractor::setApiVersion(const QString& package, const QString &version)
+{
+ return TypeDatabase::instance()->setApiVersion(package, version);
+}
+
+void ApiExtractor::setDropTypeEntries(QString dropEntries)
+{
+ dropEntries.remove(QLatin1Char(' '));
+ QStringList entries = dropEntries.split(QLatin1Char(';'));
+ TypeDatabase::instance()->setDropTypeEntries(entries);
+}
+
+AbstractMetaEnumList ApiExtractor::globalEnums() const
+{
+ Q_ASSERT(m_builder);
+ return m_builder->globalEnums();
+}
+
+AbstractMetaFunctionList ApiExtractor::globalFunctions() const
+{
+ Q_ASSERT(m_builder);
+ return m_builder->globalFunctions();
+}
+
+AbstractMetaClassList ApiExtractor::classes() const
+{
+ Q_ASSERT(m_builder);
+ return m_builder->classes();
+}
+
+AbstractMetaClassList ApiExtractor::smartPointers() const
+{
+ Q_ASSERT(m_builder);
+ return m_builder->smartPointers();
+}
+
+AbstractMetaClassList ApiExtractor::classesTopologicalSorted(const Dependencies &additionalDependencies) const
+{
+ Q_ASSERT(m_builder);
+ return m_builder->classesTopologicalSorted(Q_NULLPTR, additionalDependencies);
+}
+
+PrimitiveTypeEntryList ApiExtractor::primitiveTypes() const
+{
+ return TypeDatabase::instance()->primitiveTypes();
+}
+
+ContainerTypeEntryList ApiExtractor::containerTypes() const
+{
+ return TypeDatabase::instance()->containerTypes();
+}
+
+QSet<QString> ApiExtractor::qtMetaTypeDeclaredTypeNames() const
+{
+ Q_ASSERT(m_builder);
+ return m_builder->qtMetaTypeDeclaredTypeNames();
+}
+
+static const AbstractMetaEnum* findEnumOnClasses(AbstractMetaClassList metaClasses, const EnumTypeEntry* typeEntry)
+{
+ const AbstractMetaEnum* result = 0;
+ for (const AbstractMetaClass* metaClass : qAsConst(metaClasses)) {
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (const AbstractMetaEnum *metaEnum : enums) {
+ if (metaEnum->typeEntry() == typeEntry) {
+ result = metaEnum;
+ break;
+ }
+ }
+ if (result)
+ break;
+ result = findEnumOnClasses(metaClass->innerClasses(), typeEntry);
+ }
+ return result;
+}
+
+const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const
+{
+ if (!typeEntry)
+ return 0;
+ const AbstractMetaEnumList &globalEnums = m_builder->globalEnums();
+ for (AbstractMetaEnum* metaEnum : globalEnums) {
+ if (metaEnum->typeEntry() == typeEntry)
+ return metaEnum;
+ }
+ return findEnumOnClasses(m_builder->classes(), typeEntry);
+}
+
+const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const TypeEntry* typeEntry) const
+{
+ if (!typeEntry)
+ return 0;
+ if (typeEntry->isFlags())
+ return findAbstractMetaEnum(reinterpret_cast<const FlagsTypeEntry*>(typeEntry));
+ if (typeEntry->isEnum())
+ return findAbstractMetaEnum(reinterpret_cast<const EnumTypeEntry*>(typeEntry));
+ return 0;
+}
+
+const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const
+{
+ if (!typeEntry)
+ return 0;
+ return findAbstractMetaEnum(typeEntry->originator());
+}
+
+const AbstractMetaEnum* ApiExtractor::findAbstractMetaEnum(const AbstractMetaType* metaType) const
+{
+ if (!metaType)
+ return 0;
+ return findAbstractMetaEnum(metaType->typeEntry());
+}
+
+int ApiExtractor::classCount() const
+{
+ Q_ASSERT(m_builder);
+ return m_builder->classes().count();
+}
+
+bool ApiExtractor::run()
+{
+ if (m_builder)
+ return false;
+
+ if (m_typeSystemFileName.isEmpty()) {
+ std::cerr << "You must specify a Type System file." << std::endl;
+ return false;
+ } else if (!TypeDatabase::instance()->parseFile(m_typeSystemFileName)) {
+ std::cerr << "Cannot parse file: " << qPrintable(m_typeSystemFileName);
+ return false;
+ }
+
+ const QString pattern = QDir::tempPath() + QLatin1Char('/') +
+ QFileInfo(m_cppFileName).baseName() + QStringLiteral("_XXXXXX.hpp");
+ QTemporaryFile ppFile(pattern);
+ bool autoRemove = !qEnvironmentVariableIsSet("KEEP_TEMP_FILES");
+ // make sure that a tempfile can be written
+ if (!ppFile.open()) {
+ std::cerr << "could not create tempfile " << qPrintable(pattern)
+ << ": " << qPrintable(ppFile.errorString()) << '\n';
+ return false;
+ }
+
+ if (!appendFile(m_cppFileName, ppFile))
+ return false;
+ const QString preprocessedCppFileName = ppFile.fileName();
+ ppFile.close();
+ m_builder = new AbstractMetaBuilder;
+ m_builder->setLogDirectory(m_logDirectory);
+ m_builder->setGlobalHeader(m_cppFileName);
+ QByteArrayList arguments;
+ arguments.reserve(m_includePaths.size() + 1);
+ for (const HeaderPath &headerPath : qAsConst(m_includePaths))
+ arguments.append(HeaderPath::includeOption(headerPath));
+ arguments.append(QFile::encodeName(preprocessedCppFileName));
+ qCDebug(lcShiboken) << __FUNCTION__ << arguments;
+ const bool result = m_builder->build(arguments);
+ if (!result)
+ autoRemove = false;
+ if (!autoRemove) {
+ ppFile.setAutoRemove(false);
+ std::cerr << "Keeping temporary file: " << qPrintable(QDir::toNativeSeparators(preprocessedCppFileName)) << '\n';
+ }
+ return result;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class Container>
+static void debugFormatSequence(QDebug &d, const char *key, const Container& c)
+{
+ typedef typename Container::const_iterator ConstIt;
+ if (c.isEmpty())
+ return;
+ const ConstIt begin = c.begin();
+ const ConstIt end = c.end();
+ d << "\n " << key << '[' << c.size() << "]=(";
+ for (ConstIt it = begin; it != end; ++it) {
+ if (it != begin)
+ d << ", ";
+ d << *it;
+ }
+ d << ')';
+}
+
+QDebug operator<<(QDebug d, const ApiExtractor &ae)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "ApiExtractor(typeSystem=\"" << ae.typeSystem() << "\", cppFileName=\""
+ << ae.cppFileName() << ", ";
+ ae.m_builder->formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/ApiExtractor/apiextractor.h b/sources/shiboken2/ApiExtractor/apiextractor.h
new file mode 100644
index 000000000..ac90f5b2f
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/apiextractor.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef APIEXTRACTOR_H
+#define APIEXTRACTOR_H
+
+#include "reporthandler.h"
+#include "dependency.h"
+#include "abstractmetalang_typedefs.h"
+#include "apiextractormacros.h"
+#include "header_paths.h"
+#include "typedatabase_typedefs.h"
+#include "typesystem_typedefs.h"
+#include <QStringList>
+
+class AbstractMetaBuilder;
+class AbstractMetaClass;
+class AbstractMetaEnum;
+class AbstractMetaFunction;
+class AbstractMetaType;
+class ContainerTypeEntry;
+class EnumTypeEntry;
+class FlagsTypeEntry;
+class PrimitiveTypeEntry;
+class TypeEntry;
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+class QIODevice;
+QT_END_NAMESPACE
+
+class ApiExtractor
+{
+public:
+ ApiExtractor();
+ ~ApiExtractor();
+
+ void setTypeSystem(const QString& typeSystemFileName);
+ QString typeSystem() const { return m_typeSystemFileName; }
+ void setCppFileName(const QString& cppFileName);
+ QString cppFileName() const { return m_cppFileName; }
+ void setDebugLevel(ReportHandler::DebugLevel debugLevel);
+ void setSuppressWarnings(bool value);
+ void setSilent(bool value);
+ void addTypesystemSearchPath(const QString& path);
+ void addTypesystemSearchPath(const QStringList& paths);
+ void addIncludePath(const HeaderPath& path);
+ void addIncludePath(const HeaderPaths& paths);
+ HeaderPaths includePaths() const { return m_includePaths; }
+ void setLogDirectory(const QString& logDir);
+ bool setApiVersion(const QString& package, const QString& version);
+ void setDropTypeEntries(QString dropEntries);
+
+ AbstractMetaEnumList globalEnums() const;
+ AbstractMetaFunctionList globalFunctions() const;
+ AbstractMetaClassList classes() const;
+ AbstractMetaClassList smartPointers() const;
+ AbstractMetaClassList classesTopologicalSorted(const Dependencies &additionalDependencies = Dependencies()) const;
+ PrimitiveTypeEntryList primitiveTypes() const;
+ ContainerTypeEntryList containerTypes() const;
+ QSet<QString> qtMetaTypeDeclaredTypeNames() const;
+
+ const AbstractMetaEnum* findAbstractMetaEnum(const EnumTypeEntry* typeEntry) const;
+ const AbstractMetaEnum* findAbstractMetaEnum(const TypeEntry* typeEntry) const;
+ const AbstractMetaEnum* findAbstractMetaEnum(const FlagsTypeEntry* typeEntry) const;
+ const AbstractMetaEnum* findAbstractMetaEnum(const AbstractMetaType* metaType) const;
+
+ int classCount() const;
+
+ bool run();
+private:
+ QString m_typeSystemFileName;
+ QString m_cppFileName;
+ HeaderPaths m_includePaths;
+ AbstractMetaBuilder* m_builder;
+ QString m_logDirectory;
+
+ // disable copy
+ ApiExtractor(const ApiExtractor&);
+ ApiExtractor& operator=(const ApiExtractor&);
+#ifndef QT_NO_DEBUG_STREAM
+ friend QDebug operator<<(QDebug d, const ApiExtractor &ae);
+#endif
+};
+
+#endif // APIEXTRACTOR_H
diff --git a/sources/shiboken2/ApiExtractor/apiextractormacros.h b/sources/shiboken2/ApiExtractor/apiextractormacros.h
new file mode 100644
index 000000000..41a710773
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/apiextractormacros.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef APIEXTRACTORMACROS_H
+#define APIEXTRACTORMACROS_H
+
+
+// APIEXTRACTOR_API is used for the public API symbols.
+#if defined _WIN32
+ #define APIEXTRACTOR_DEPRECATED(func) __declspec(deprecated) func
+#elif __GNUC__ >= 4
+ #define APIEXTRACTOR_DEPRECATED(func) func __attribute__ ((deprecated))
+#else
+ #define APIEXTRACTOR_DEPRECATED(func) func
+#endif
+#endif
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
new file mode 100644
index 000000000..dc0c59dd5
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.cpp
@@ -0,0 +1,770 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clangbuilder.h"
+#include "compilersupport.h"
+#include "clangutils.h"
+
+#include <codemodel.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QHash>
+#include <QtCore/QMap>
+#include <QtCore/QString>
+#include <QtCore/QStack>
+#include <QtCore/QVector>
+
+#include <string.h>
+
+#if QT_VERSION < 0x050800
+# define Q_FALLTHROUGH() (void)0
+#endif
+
+namespace clang {
+
+static inline QString colonColon() { return QStringLiteral("::"); }
+static inline QString templateBrackets() { return QStringLiteral("<>"); }
+
+static inline bool isClassCursor(const CXCursor &c)
+{
+ return c.kind == CXCursor_ClassDecl || c.kind == CXCursor_StructDecl
+ || c.kind == CXCursor_ClassTemplate
+ || c.kind == CXCursor_ClassTemplatePartialSpecialization;
+}
+
+static inline bool withinClassDeclaration(const CXCursor &cursor)
+{
+ return isClassCursor(clang_getCursorLexicalParent(cursor));
+}
+
+static QString fixTypeName(QString t)
+{
+ // Fix "Foo &" -> "Foo&", similarly "Bar **" -> "Bar**"
+ int pos = t.size() - 1;
+ for (; pos >= 0 && (t.at(pos) == QLatin1Char('&') || t.at(pos) == QLatin1Char('*')); --pos) {}
+ if (pos > 0 && t.at(pos) == QLatin1Char(' '))
+ t.remove(pos, 1);
+ return t;
+}
+
+// Insert template parameter to class name: "Foo<>" -> "Foo<T1>" -> "Foo<T1,T2>"
+// This needs to be done immediately when template parameters are encountered since
+// the class name "Foo<T1,T2>" is the scope for nested items.
+static bool insertTemplateParameterIntoClassName(const QString &parmName, QString *name)
+{
+ if (Q_UNLIKELY(!name->endsWith(QLatin1Char('>'))))
+ return false;
+ const bool needsComma = name->at(name->size() - 2) != QLatin1Char('<');
+ const int insertionPos = name->size() - 1;
+ name->insert(insertionPos, parmName);
+ if (needsComma)
+ name->insert(insertionPos, QLatin1Char(','));
+ return true;
+}
+
+static inline bool insertTemplateParameterIntoClassName(const QString &parmName,
+ const ClassModelItem &item)
+{
+ QString name = item->name();
+ const bool result = insertTemplateParameterIntoClassName(parmName, &name);
+ item->setName(name);
+ return result;
+}
+
+static inline CodeModel::AccessPolicy accessPolicy(CX_CXXAccessSpecifier access)
+{
+ CodeModel::AccessPolicy result = CodeModel::Public;
+ switch (access) {
+ case CX_CXXProtected:
+ result = CodeModel::Protected;
+ break;
+ case CX_CXXPrivate:
+ result = CodeModel::Private;
+ break;
+ default:
+ break;
+ }
+ return result;
+}
+
+static void setFileName(const CXCursor &cursor, _CodeModelItem *item)
+{
+ const SourceRange range = getCursorRange(cursor);
+ if (!range.first.file.isEmpty()) { // Has been observed to be 0 for invalid locations
+ item->setFileName(QDir::cleanPath(range.first.file));
+ item->setStartPosition(int(range.first.line), int(range.first.column));
+ item->setEndPosition(int(range.second.line), int(range.second.column));
+ }
+}
+
+class BuilderPrivate {
+public:
+ typedef QHash<CXCursor, ClassModelItem> CursorClassHash;
+ typedef QHash<CXCursor, TypeDefModelItem> CursorTypedefHash;
+
+ explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel)
+ {
+ m_scopeStack.push(NamespaceModelItem(new _FileModelItem(m_model)));
+ }
+
+ // Determine scope from top item. Note that the scope list does not necessarily
+ // match the scope stack in case of forward-declared inner classes whose definition
+ // appears in the translation unit while the scope is the outer class.
+ void updateScope()
+ {
+ if (m_scopeStack.size() <= 1)
+ m_scope.clear();
+ else
+ m_scope = m_scopeStack.back()->scope() << m_scopeStack.back()->name();
+ }
+
+ void pushScope(const ScopeModelItem &i)
+ {
+ m_scopeStack.push(i);
+ updateScope();
+ }
+
+ void popScope()
+ {
+ m_scopeStack.pop();
+ updateScope();
+ }
+
+ bool addClass(const CXCursor &cursor, CodeModel::ClassType t);
+ FunctionModelItem createFunction(const CXCursor &cursor,
+ CodeModel::FunctionType t = CodeModel::Normal) const;
+ FunctionModelItem createMemberFunction(const CXCursor &cursor,
+ CodeModel::FunctionType t = CodeModel::Normal) const;
+ void qualifyConstructor(const CXCursor &cursor);
+ TypeInfo createTypeInfo(const CXType &type) const;
+ TypeInfo createTypeInfo(const CXCursor &cursor) const
+ { return createTypeInfo(clang_getCursorType(cursor)); }
+
+ TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const;
+ TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const;
+ void addField(const CXCursor &cursor);
+
+ QString cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const;
+ void addBaseClass(const CXCursor &cursor);
+
+ template <class Item>
+ void qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer<Item> &item) const;
+
+ BaseVisitor *m_baseVisitor;
+ CodeModel *m_model;
+
+ QStack<ScopeModelItem> m_scopeStack;
+ QStringList m_scope;
+ // Store all classes by cursor so that base classes can be found and inner
+ // classes can be correctly parented in case of forward-declared inner classes
+ // (QMetaObject::Connection)
+ CursorClassHash m_cursorClassHash;
+ CursorTypedefHash m_cursorTypedefHash;
+
+ ClassModelItem m_currentClass;
+ EnumModelItem m_currentEnum;
+ FunctionModelItem m_currentFunction;
+ ArgumentModelItem m_currentArgument;
+ VariableModelItem m_currentField;
+
+ int m_anonymousEnumCount = 0;
+ CodeModel::FunctionType m_currentFunctionType = CodeModel::Normal;
+};
+
+bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t)
+{
+ QString className = getCursorSpelling(cursor);
+ m_currentClass.reset(new _ClassModelItem(m_model, className));
+ setFileName(cursor, m_currentClass.data());
+ m_currentClass->setClassType(t);
+ // Some inner class? Note that it does not need to be (lexically) contained in a
+ // class since it is possible to forward declare an inner class:
+ // class QMetaObject { class Connection; }
+ // class QMetaObject::Connection {}
+ const CXCursor semPar = clang_getCursorSemanticParent(cursor);
+ if (isClassCursor(semPar)) {
+ const CursorClassHash::const_iterator it = m_cursorClassHash.constFind(semPar);
+ if (it == m_cursorClassHash.constEnd()) {
+ const QString message = QStringLiteral("Unable to find parent of inner class ") + className;
+ const Diagnostic d(message, cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ m_baseVisitor->appendDiagnostic(d);
+ return false;
+ }
+ const ClassModelItem &containingClass = it.value();
+ containingClass->addClass(m_currentClass);
+ m_currentClass->setScope(containingClass->scope() << containingClass->name());
+ } else {
+ m_currentClass->setScope(m_scope);
+ m_scopeStack.back()->addClass(m_currentClass);
+ }
+ pushScope(m_currentClass);
+ m_cursorClassHash.insert(cursor, m_currentClass);
+ return true;
+}
+
+FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor,
+ CodeModel::FunctionType t) const
+{
+ QString name = getCursorSpelling(cursor);
+ // Apply type fixes to "operator X &" -> "operator X&"
+ if (name.startsWith(QLatin1String("operator ")))
+ name = fixTypeName(name);
+ FunctionModelItem result(new _FunctionModelItem(m_model, name));
+ setFileName(cursor, result.data());
+ result->setType(createTypeInfo(clang_getCursorResultType(cursor)));
+ result->setFunctionType(t);
+ result->setScope(m_scope);
+ result->setStatic(clang_Cursor_getStorageClass(cursor) == CX_SC_Static);
+ return result;
+}
+
+FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor,
+ CodeModel::FunctionType t) const
+{
+ FunctionModelItem result = createFunction(cursor, t);
+ result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ result->setConstant(clang_CXXMethod_isConst(cursor) != 0);
+ result->setStatic(clang_CXXMethod_isStatic(cursor) != 0);
+ result->setVirtual(clang_CXXMethod_isVirtual(cursor) != 0);
+ result->setAbstract(clang_CXXMethod_isPureVirtual(cursor) != 0);
+ result->setFunctionType(m_currentFunctionType);
+ return result;
+}
+
+// For CXCursor_Constructor, on endToken().
+void BuilderPrivate::qualifyConstructor(const CXCursor &cursor)
+{
+ // Clang does not tell us whether a constructor is explicit, preventing it
+ // from being used for implicit conversions. Try to guess whether a
+ // constructor is explicit in the C++99 sense (1 parameter) by checking for
+ // isConvertingConstructor() == 0. Fixme: The notion of "isConvertingConstructor"
+ // should be used in the code model instead of "explicit"
+ if (clang_CXXConstructor_isDefaultConstructor(cursor) == 0
+ && m_currentFunction->arguments().size() == 1
+ && clang_CXXConstructor_isCopyConstructor(cursor) == 0
+ && clang_CXXConstructor_isMoveConstructor(cursor) == 0) {
+ m_currentFunction->setExplicit(clang_CXXConstructor_isConvertingConstructor(cursor) == 0);
+ }
+}
+
+TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCursor &cursor) const
+{
+ return TemplateParameterModelItem(new _TemplateParameterModelItem(m_model, getCursorSpelling(cursor)));
+}
+
+TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const
+{
+ TemplateParameterModelItem result = createTemplateParameter(cursor);
+ result->setType(createTypeInfo(cursor));
+ return result;
+}
+
+// CXCursor_VarDecl, CXCursor_FieldDecl cursors
+void BuilderPrivate::addField(const CXCursor &cursor)
+{
+ VariableModelItem field(new _VariableModelItem(m_model, getCursorSpelling(cursor)));
+ field->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ field->setScope(m_scope);
+ field->setType(createTypeInfo(cursor));
+ field->setMutable(clang_CXXField_isMutable(cursor) != 0);
+ m_currentField = field;
+ m_scopeStack.back()->addVariable(field);
+}
+
+// Array helpers: Parse "a[2][4]" into a list of dimensions
+
+struct ArrayDimensionResult
+{
+ QVector<QStringRef> dimensions;
+ int position;
+};
+
+static ArrayDimensionResult arrayDimensions(const QString &typeName)
+{
+ ArrayDimensionResult result;
+ result.position = typeName.indexOf(QLatin1Char('['));
+ for (int openingPos = result.position; openingPos != -1; ) {
+ const int closingPos = typeName.indexOf(QLatin1Char(']'), openingPos + 1);
+ if (closingPos == -1)
+ break;
+ result.dimensions.append(typeName.midRef(openingPos + 1, closingPos - openingPos - 1));
+ openingPos = typeName.indexOf(QLatin1Char('['), closingPos + 1);
+ }
+ return result;
+}
+
+// Array helpers: Parse "a[2][4]" into a list of dimensions or "" for none
+static QStringList parseArrayArgs(const CXType &type, QString *typeName)
+{
+ const ArrayDimensionResult dimensions = arrayDimensions(*typeName);
+ Q_ASSERT(!dimensions.dimensions.isEmpty());
+
+ QStringList result;
+ // get first dimension from clang, preferably.
+ // "a[]" is seen as pointer by Clang, set special indicator ""
+ const long long size = clang_getArraySize(type);
+ result.append(size >= 0 ? QString::number(size) : QString());
+ // Parse out remaining dimensions
+ for (int i = 1, count = dimensions.dimensions.size(); i < count; ++i)
+ result.append(dimensions.dimensions.at(i).toString());
+ typeName->truncate(dimensions.position);
+ return result;
+}
+
+TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const
+{
+ if (type.kind == CXType_Pointer) { // Check for function pointers, first.
+ const CXType pointeeType = clang_getPointeeType(type);
+ const int argCount = clang_getNumArgTypes(pointeeType);
+ if (argCount >= 0) {
+ TypeInfo result = createTypeInfo(clang_getResultType(pointeeType));
+ result.setFunctionPointer(true);
+ for (int a = 0; a < argCount; ++a)
+ result.addArgument(createTypeInfo(clang_getArgType(pointeeType, unsigned(a))));
+ return result;
+ }
+ }
+
+ TypeInfo typeInfo;
+ QString typeName = fixTypeName(getTypeName(type));
+
+ int indirections = 0;
+ // "int **"
+ for ( ; typeName.endsWith(QLatin1Char('*')) ; ++indirections)
+ typeName.chop(1);
+ typeInfo.setIndirections(indirections);
+ // "int &&"
+ if (typeName.endsWith(QLatin1String("&&"))) {
+ typeName.chop(2);
+ typeInfo.setReferenceType(RValueReference);
+ } else if (typeName.endsWith(QLatin1Char('&'))) { // "int &"
+ typeName.chop(1);
+ typeInfo.setReferenceType(LValueReference);
+ }
+
+ // "int [3], int[]"
+ if (type.kind == CXType_ConstantArray || type.kind == CXType_IncompleteArray
+ || type.kind == CXType_VariableArray || type.kind == CXType_DependentSizedArray) {
+ typeInfo.setArrayElements(parseArrayArgs(type, &typeName));
+ }
+
+ bool isConstant = clang_isConstQualifiedType(type) != 0;
+ // A "char *const" parameter, is considered to be const-qualified by Clang, but
+ // not in the TypeInfo sense (corresponds to "char *" and not "const char *").
+ if (type.kind == CXType_Pointer && isConstant && typeName.endsWith(QLatin1String("const"))) {
+ typeName.chop(5);
+ typeName = typeName.trimmed();
+ isConstant = false;
+ }
+ // Clang has been observed to return false for "const int .."
+ if (!isConstant && typeName.startsWith(QLatin1String("const "))) {
+ typeName.remove(0, 6);
+ isConstant = true;
+ }
+ typeInfo.setConstant(isConstant);
+
+ // clang_isVolatileQualifiedType() returns true for "volatile int", but not for "volatile int *"
+ if (typeName.startsWith(QLatin1String("volatile "))) {
+ typeName.remove(0, 9);
+ typeInfo.setVolatile(true);
+ }
+
+ typeName = typeName.trimmed();
+
+ typeInfo.setQualifiedName(typeName.split(colonColon()));
+ // 3320:CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); function ptr types?
+ return typeInfo;
+}
+
+// extract an expression from the cursor via source
+// CXCursor_EnumConstantDecl, ParmDecl (a = Flag1 | Flag2)
+QString BuilderPrivate::cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor) const
+{
+ BaseVisitor::CodeSnippet snippet = bv->getCodeSnippet(cursor);
+ const char *equalSign = std::find(snippet.first, snippet.second, '=');
+ if (equalSign == snippet.second)
+ return QString();
+ ++equalSign;
+ return QString::fromLocal8Bit(equalSign, int(snippet.second - equalSign)).trimmed();
+}
+
+// Add a base class to the current class from CXCursor_CXXBaseSpecifier
+void BuilderPrivate::addBaseClass(const CXCursor &cursor)
+{
+ const CXType inheritedType = clang_getCursorType(cursor); // Note spelling has "struct baseClass",
+ QString baseClassName = getTypeName(inheritedType); // use type.
+ const CXCursor declCursor = clang_getTypeDeclaration(inheritedType);
+ const CursorClassHash::const_iterator it = m_cursorClassHash.constFind(declCursor);
+ if (it == m_cursorClassHash.constEnd()) {
+ // Set unqualified name. This happens in cases like "class X : public std::list<...>"
+ // "template<class T> class Foo : public T" and standard types like true_type, false_type.
+ m_currentClass->setBaseClasses(m_currentClass->baseClasses() << baseClassName);
+ return;
+ }
+ // Completely qualify the class name by looking it up and taking its scope
+ // plus the actual baseClass stripped off any scopes. Consider:
+ // namespace std {
+ // template <class T> class vector {};
+ // namespace n {
+ // class Foo : public vector<int> {};
+ // }
+ // }
+ // should have "std::vector<int>" as base class (whereas the type of the base class is
+ // "std::vector<T>").
+ const QStringList &baseScope = it.value()->scope();
+ if (!baseScope.isEmpty()) {
+ const int lastSep = baseClassName.lastIndexOf(colonColon());
+ if (lastSep >= 0)
+ baseClassName.remove(0, lastSep + colonColon().size());
+ baseClassName.prepend(colonColon());
+ baseClassName.prepend(baseScope.join(colonColon()));
+ }
+ m_currentClass->setBaseClasses(m_currentClass->baseClasses() << baseClassName);
+}
+
+static inline CXCursor definitionFromTypeRef(const CXCursor &typeRefCursor)
+{
+ Q_ASSERT(typeRefCursor.kind == CXCursor_TypeRef);
+ return clang_getTypeDeclaration(clang_getCursorType(typeRefCursor));
+}
+
+// Qualify function arguments or fields that are typedef'ed from another scope:
+// enum ConversionFlag {};
+// typedef QFlags<ConversionFlag> ConversionFlags;
+// class QTextCodec {
+// enum ConversionFlag {};
+// typedef QFlags<ConversionFlag> ConversionFlags;
+// struct ConverterState {
+// explicit ConverterState(ConversionFlags);
+// ^^ qualify to QTextCodec::ConversionFlags
+// ConversionFlags m_flags;
+// ^^ ditto
+
+template <class Item> // ArgumentModelItem, VariableModelItem
+void BuilderPrivate::qualifyTypeDef(const CXCursor &typeRefCursor, const QSharedPointer<Item> &item) const
+{
+ typedef typename CursorTypedefHash::const_iterator ConstIt;
+
+ TypeInfo type = item->type();
+ if (type.qualifiedName().size() == 1) { // item's type is unqualified.
+ const ConstIt it = m_cursorTypedefHash.constFind(definitionFromTypeRef(typeRefCursor));
+ if (it != m_cursorTypedefHash.constEnd() && !it.value()->scope().isEmpty()) {
+ type.setQualifiedName(it.value()->scope() + type.qualifiedName());
+ item->setType(type);
+ }
+ }
+}
+
+Builder::Builder()
+{
+ d = new BuilderPrivate(this);
+}
+
+Builder::~Builder()
+{
+ delete d;
+}
+
+bool Builder::visitLocation(const CXSourceLocation &location) const
+{
+ return !clang_Location_isInSystemHeader(location);
+}
+
+FileModelItem Builder::dom() const
+{
+ Q_ASSERT(!d->m_scopeStack.isEmpty());
+ return qSharedPointerDynamicCast<_FileModelItem>(d->m_scopeStack.constFirst());
+}
+
+static QString msgOutOfOrder(const CXCursor &cursor, const char *expectedScope)
+{
+ return getCursorKindName(cursor.kind) + QLatin1Char(' ')
+ + getCursorSpelling(cursor) + QLatin1String(" encountered outside ")
+ + QLatin1String(expectedScope) + QLatin1Char('.');
+}
+
+static CodeModel::ClassType codeModelClassTypeFromCursor(CXCursorKind kind)
+{
+ CodeModel::ClassType result = CodeModel::Class;
+ if (kind == CXCursor_UnionDecl)
+ result = CodeModel::Union;
+ else if (kind == CXCursor_StructDecl)
+ result = CodeModel::Struct;
+ return result;
+}
+
+BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+{
+ switch (cursor.kind) {
+ case CXCursor_CXXAccessSpecifier:
+ d->m_currentFunctionType = CodeModel::Normal;
+ break;
+ case CXCursor_AnnotateAttr: {
+ const QString annotation = getCursorSpelling(cursor);
+ if (annotation == QLatin1String("qt_slot"))
+ d->m_currentFunctionType = CodeModel::Slot;
+ else if (annotation == QLatin1String("qt_signal"))
+ d->m_currentFunctionType = CodeModel::Signal;
+ else
+ d->m_currentFunctionType = CodeModel::Normal;
+ }
+ break;
+ case CXCursor_CXXBaseSpecifier:
+ if (d->m_currentClass.isNull()) {
+ const Diagnostic d(msgOutOfOrder(cursor, "class"), cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ appendDiagnostic(d);
+ return Error;
+ }
+ d->addBaseClass(cursor);
+ break;
+ case CXCursor_ClassDecl:
+ case CXCursor_UnionDecl:
+ case CXCursor_StructDecl:
+ if (clang_isCursorDefinition(cursor) == 0)
+ return Skip;
+ if (!d->addClass(cursor, codeModelClassTypeFromCursor(cursor.kind)))
+ return Error;
+ break;
+ case CXCursor_ClassTemplate:
+ case CXCursor_ClassTemplatePartialSpecialization:
+ if (clang_isCursorDefinition(cursor) == 0)
+ return Skip;
+ d->addClass(cursor, CodeModel::Class);
+ d->m_currentClass->setName(d->m_currentClass->name() + templateBrackets());
+ d->m_scope.back() += templateBrackets();
+ break;
+ case CXCursor_EnumDecl: {
+ QString name = getCursorSpelling(cursor);
+ const bool anonymous = name.isEmpty();
+ if (anonymous)
+ name = QStringLiteral("enum_") + QString::number(++d->m_anonymousEnumCount);
+ d->m_currentEnum.reset(new _EnumModelItem(d->m_model, name));
+ setFileName(cursor, d->m_currentEnum.data());
+ d->m_currentEnum->setScope(d->m_scope);
+ d->m_currentEnum->setAnonymous(anonymous);
+ if (!qSharedPointerDynamicCast<_ClassModelItem>(d->m_scopeStack.back()).isNull())
+ d->m_currentEnum->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ d->m_scopeStack.back()->addEnum(d->m_currentEnum);
+ }
+ break;
+ case CXCursor_EnumConstantDecl: {
+ const QString name = getCursorSpelling(cursor);
+ if (d->m_currentEnum.isNull()) {
+ const Diagnostic d(msgOutOfOrder(cursor, "enum"), cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ appendDiagnostic(d);
+ return Error;
+ }
+ EnumeratorModelItem enumConstant(new _EnumeratorModelItem(d->m_model, name));
+ enumConstant->setValue(d->cursorValueExpression(this, cursor));
+ d->m_currentEnum->addEnumerator(enumConstant);
+ }
+ break;
+ case CXCursor_VarDecl:
+ // static class members are seen as CXCursor_VarDecl
+ if (!d->m_currentClass.isNull() && isClassCursor(clang_getCursorSemanticParent(cursor))) {
+ d->addField(cursor);
+ d->m_currentField->setStatic(true);
+ }
+ break;
+ case CXCursor_FieldDecl:
+ d->addField(cursor);
+ break;
+#if CINDEX_VERSION_MAJOR > 0 || CINDEX_VERSION_MINOR >= 37 // Clang 4.0
+ case CXCursor_FriendDecl:
+ return Skip;
+#endif
+ case CXCursor_Constructor:
+ case CXCursor_Destructor: // Note: Also use clang_CXXConstructor_is..Constructor?
+ case CXCursor_CXXMethod:
+ case CXCursor_ConversionFunction:
+ // Skip inline member functions outside class, only go by declarations inside class
+ if (!withinClassDeclaration(cursor))
+ return Skip;
+ d->m_currentFunction = d->createMemberFunction(cursor, CodeModel::Normal);
+ d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+ break;
+ // Not fully supported, currently, seen as normal function
+ // Note: May appear inside class (member template) or outside (free template).
+ case CXCursor_FunctionTemplate: {
+ const CXCursor semParent = clang_getCursorSemanticParent(cursor);
+ if (isClassCursor(semParent)) {
+ if (semParent == clang_getCursorLexicalParent(cursor)) {
+ d->m_currentFunction = d->createMemberFunction(cursor, CodeModel::Normal);
+ d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+ break;
+ } else {
+ return Skip; // inline member functions outside class
+ }
+ }
+ }
+ Q_FALLTHROUGH(); // fall through to free template function.
+ case CXCursor_FunctionDecl:
+ d->m_currentFunction = d->createFunction(cursor);
+ d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+ break;
+ case CXCursor_Namespace: {
+ const QString name = getCursorSpelling(cursor);
+ const NamespaceModelItem parentNamespaceItem = qSharedPointerDynamicCast<_NamespaceModelItem>(d->m_scopeStack.back());
+ if (parentNamespaceItem.isNull()) {
+ const QString message = msgOutOfOrder(cursor, "namespace")
+ + QLatin1String(" (current scope: ") + d->m_scopeStack.back()->name() + QLatin1Char(')');
+ const Diagnostic d(message, cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ appendDiagnostic(d);
+ return Error;
+ }
+ // If possible, continue existing namespace (as otherwise, all headers
+ // where a namespace is continued show up in the type database).
+ NamespaceModelItem namespaceItem = parentNamespaceItem->findNamespace(name);
+ if (namespaceItem.isNull()) {
+ namespaceItem.reset(new _NamespaceModelItem(d->m_model, name));
+ setFileName(cursor, namespaceItem.data());
+ namespaceItem->setScope(d->m_scope);
+ parentNamespaceItem->addNamespace(namespaceItem);
+ }
+ d->pushScope(namespaceItem);
+ }
+ break;
+ case CXCursor_ParmDecl:
+ // Skip in case of nested CXCursor_ParmDecls in case one parameter is a function pointer
+ // and function pointer typedefs.
+ if (d->m_currentArgument.isNull() && !d->m_currentFunction.isNull()) {
+ const QString name = getCursorSpelling(cursor);
+ d->m_currentArgument.reset(new _ArgumentModelItem(d->m_model, name));
+ d->m_currentArgument->setType(d->createTypeInfo(cursor));
+ d->m_currentFunction->addArgument(d->m_currentArgument);
+ QString defaultValueExpression = d->cursorValueExpression(this, cursor);
+ if (!defaultValueExpression.isEmpty()) {
+ d->m_currentArgument->setDefaultValueExpression(defaultValueExpression);
+ d->m_currentArgument->setDefaultValue(true);
+ }
+ } else {
+ return Skip;
+ }
+ break;
+ case CXCursor_TemplateTypeParameter:
+ case CXCursor_NonTypeTemplateParameter: {
+ const TemplateParameterModelItem tItem = cursor.kind == CXCursor_TemplateTemplateParameter
+ ? d->createTemplateParameter(cursor) : d->createNonTypeTemplateParameter(cursor);
+ // Apply to function/member template?
+ if (!d->m_currentFunction.isNull()) {
+ d->m_currentFunction->setTemplateParameters(d->m_currentFunction->templateParameters() << tItem);
+ } else if (!d->m_currentClass.isNull()) { // Apply to class
+ const QString &tplParmName = tItem->name();
+ if (Q_UNLIKELY(!insertTemplateParameterIntoClassName(tplParmName, d->m_currentClass)
+ || !insertTemplateParameterIntoClassName(tplParmName, &d->m_scope.back()))) {
+ const QString message = QStringLiteral("Error inserting template parameter \"") + tplParmName
+ + QStringLiteral("\" into ") + d->m_currentClass->name();
+ const Diagnostic d(message, cursor, CXDiagnostic_Error);
+ qWarning() << d;
+ appendDiagnostic(d);
+ return Error;
+ }
+ d->m_currentClass->setTemplateParameters(d->m_currentClass->templateParameters() << tItem);
+ }
+ }
+ break;
+ case CXCursor_TypeAliasDecl:
+ case CXCursor_TypeAliasTemplateDecl: // May contain nested CXCursor_TemplateTypeParameter
+ return Skip;
+ case CXCursor_TypedefDecl: {
+ const QString name = getCursorSpelling(cursor);
+ TypeDefModelItem item(new _TypeDefModelItem(d->m_model, name));
+ setFileName(cursor, item.data());
+ item->setType(d->createTypeInfo(clang_getTypedefDeclUnderlyingType(cursor)));
+ item->setScope(d->m_scope);
+ d->m_scopeStack.back()->addTypeDef(item);
+ d->m_cursorTypedefHash.insert(cursor, item);
+ }
+ break;
+ case CXCursor_TypeRef:
+ if (!d->m_currentFunction.isNull()) {
+ if (d->m_currentArgument.isNull())
+ d->qualifyTypeDef(cursor, d->m_currentFunction); // return type
+ else
+ d->qualifyTypeDef(cursor, d->m_currentArgument);
+ } else if (!d->m_currentField.isNull()) {
+ d->qualifyTypeDef(cursor, d->m_currentField);
+ }
+ break;
+ default:
+ break;
+ }
+ return BaseVisitor::Recurse;
+}
+
+bool Builder::endToken(const CXCursor &cursor)
+{
+ switch (cursor.kind) {
+ case CXCursor_UnionDecl:
+ case CXCursor_ClassDecl:
+ case CXCursor_StructDecl:
+ case CXCursor_ClassTemplate:
+ case CXCursor_ClassTemplatePartialSpecialization:
+ d->popScope();
+ // Continue in outer class after leaving inner class?
+ if (ClassModelItem lastClass = qSharedPointerDynamicCast<_ClassModelItem>(d->m_scopeStack.back()))
+ d->m_currentClass = lastClass;
+ else
+ d->m_currentClass.clear();
+ d->m_currentFunctionType = CodeModel::Normal;
+ break;
+ case CXCursor_EnumDecl:
+ d->m_currentEnum.clear();
+ break;
+ case CXCursor_VarDecl:
+ case CXCursor_FieldDecl:
+ d->m_currentField.clear();
+ break;
+ case CXCursor_Constructor:
+ d->qualifyConstructor(cursor);
+ d->m_currentFunction.clear();
+ break;
+ case CXCursor_Destructor:
+ case CXCursor_CXXMethod:
+ case CXCursor_FunctionDecl:
+ case CXCursor_FunctionTemplate:
+ d->m_currentFunction.clear();
+ break;
+ case CXCursor_Namespace:
+ d->popScope();
+ break;
+ case CXCursor_ParmDecl:
+ d->m_currentArgument.clear();
+ break;
+ default:
+ break;
+ }
+ return true;
+}
+
+} // namespace clang
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h
new file mode 100644
index 000000000..c97b7d2b7
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangbuilder.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLANGBUILDER_H
+#define CLANGBUILDER_H
+
+#include "clangparser.h"
+
+#include <codemodel_fwd.h>
+
+namespace clang {
+
+class BuilderPrivate;
+
+class Builder : public BaseVisitor {
+public:
+ Builder();
+ ~Builder();
+
+ bool visitLocation(const CXSourceLocation &location) const override;
+
+ StartTokenResult startToken(const CXCursor &cursor) override;
+ bool endToken(const CXCursor &cursor) override;
+
+ FileModelItem dom() const;
+
+private:
+ BuilderPrivate *d;
+};
+
+} // namespace clang
+
+#endif // CLANGBUILDER_H
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp
new file mode 100644
index 000000000..8d0fd098a
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.cpp
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clangdebugutils.h"
+#include "clangutils.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+
+#include <string.h>
+
+#ifndef QT_NO_DEBUG_STREAM
+
+#ifdef Q_OS_WIN
+const char pathSep = '\\';
+#else
+const char pathSep = '/';
+#endif
+
+static const char *baseName(const char *fileName)
+{
+ const char *b = strrchr(fileName, pathSep);
+ return b ? b + 1 : fileName;
+}
+
+QDebug operator<<(QDebug s, const CXString &cs)
+{
+ s << clang_getCString(cs);
+ return s;
+}
+
+QDebug operator<<(QDebug s, CXCursorKind cursorKind) // Enum
+{
+ const CXString kindName = clang_getCursorKindSpelling(cursorKind);
+ s << kindName;
+ clang_disposeString(kindName);
+ return s;
+}
+
+static const char *accessSpecsStrings[]
+{
+ // CX_CXXInvalidAccessSpecifier, CX_CXXPublic, CX_CXXProtected, CX_CXXPrivate
+ "invalid", "public", "protected", "private"
+};
+
+QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac)
+{
+ s << accessSpecsStrings[ac];
+ return s;
+}
+
+QDebug operator<<(QDebug s, const CXType &t)
+{
+ CXString typeSpelling = clang_getTypeSpelling(t);
+ s << typeSpelling;
+ clang_disposeString(typeSpelling);
+ return s;
+}
+
+QDebug operator<<(QDebug s, const CXCursor &cursor)
+{
+ QDebugStateSaver saver(s);
+ s.nospace();
+ s.noquote();
+ const CXCursorKind kind = clang_getCursorKind(cursor);
+ s << kind;
+ if (kind >= CXCursor_FirstInvalid && kind <= CXCursor_LastInvalid)
+ return s;
+ const CXType type = clang_getCursorType(cursor);
+ switch (kind) {
+ case CXCursor_CXXAccessSpecifier:
+ s << ' ' << clang_getCXXAccessSpecifier(cursor);
+ break;
+ case CXCursor_CXXBaseSpecifier:
+ s << ", inherits=\"" << clang::getCursorSpelling(clang_getTypeDeclaration(type)) << '"';
+ break;
+ case CXCursor_CXXMethod:
+ case CXCursor_FunctionDecl:
+ case CXCursor_ConversionFunction:
+ s << ", result type=\"" << clang_getCursorResultType(cursor) << '"';
+ break;
+ case CXCursor_TypedefDecl:
+ s << ", underlyingType=\"" << clang_getTypedefDeclUnderlyingType(cursor) << '"';
+ break;
+ default:
+ break;
+ }
+
+ if (type.kind != CXType_Invalid)
+ s << ", type=\"" << type << '"';
+ if (clang_Cursor_hasAttrs(cursor))
+ s << ", [attrs]";
+
+ const QString cursorSpelling = clang::getCursorSpelling(cursor);
+ if (!cursorSpelling.isEmpty())
+ s << ", spelling=\"" << cursorSpelling << '"';
+ CXString cursorDisplay = clang_getCursorDisplayName(cursor);
+ if (const char *dpy = clang_getCString(cursorDisplay)) {
+ const QString display = QString::fromUtf8(dpy);
+ if (display != cursorSpelling)
+ s << ", display=\"" << dpy << '"';
+ }
+ clang_disposeString(cursorDisplay);
+ return s;
+}
+
+QDebug operator<<(QDebug s, const CXSourceLocation &location)
+{
+ QDebugStateSaver saver(s);
+ s.nospace();
+ CXFile file; // void *
+ unsigned line;
+ unsigned column;
+ unsigned offset;
+ clang_getExpansionLocation(location, &file, &line, &column, &offset);
+ const CXString cxFileName = clang_getFileName(file);
+ // Has been observed to be 0 for invalid locations
+ if (const char *cFileName = clang_getCString(cxFileName))
+ s << baseName(cFileName) << ':';
+ s << line << ':' << column;
+ clang_disposeString(cxFileName);
+ return s;
+}
+
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h
new file mode 100644
index 000000000..323efdd2a
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangdebugutils.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLANGDEBUGUTILS_H
+#define CLANGDEBUGUTILS_H
+
+#include <QtCore/QtGlobal>
+
+#include <clang-c/Index.h>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+QT_FORWARD_DECLARE_CLASS(QString)
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug s, const CXString &cs);
+QDebug operator<<(QDebug s, CXCursorKind cursorKind);
+QDebug operator<<(QDebug s, CX_CXXAccessSpecifier ac);
+QDebug operator<<(QDebug s, const CXType &t);
+QDebug operator<<(QDebug s, const CXCursor &cursor);
+QDebug operator<<(QDebug s, const CXSourceLocation &location);
+#endif // !QT_NO_DEBUG_STREAM
+
+#endif // CLANGDEBUGUTILS_H
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp
new file mode 100644
index 000000000..eb3be115c
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangparser.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clangparser.h"
+#include "clangutils.h"
+#include "clangdebugutils.h"
+#include "compilersupport.h"
+
+#include <QtCore/QByteArrayList>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QScopedArrayPointer>
+#include <QtCore/QString>
+
+namespace clang {
+
+SourceFileCache::Snippet SourceFileCache::getCodeSnippet(const CXCursor &cursor)
+{
+ Snippet result(nullptr, nullptr);
+ const SourceRange range = getCursorRange(cursor);
+ if (range.first.file.isEmpty() || range.second.file != range.first.file)
+ return result;
+ FileBufferCache::Iterator it = m_fileBufferCache.find(range.first.file);
+ if (it == m_fileBufferCache.end()) {
+ QFile file(range.first.file);
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning().noquote().nospace()
+ << "Can't open " << QDir::toNativeSeparators(range.first.file)
+ << ": " << file.errorString();
+ return result;
+ }
+ it = m_fileBufferCache.insert(range.first.file, file.readAll());
+ }
+
+ const unsigned pos = range.first.offset;
+ const unsigned end = range.second.offset;
+ const QByteArray &contents = it.value();
+ if (end >= unsigned(contents.size())) {
+ qWarning().noquote().nospace() << "Range end " << end << " is above size of "
+ << range.first.file << " (" << contents.size() << ')';
+ return result;
+ }
+ result.first = contents.constData() + pos;
+ result.second = contents.constData() + end;
+ return result;
+}
+
+BaseVisitor::BaseVisitor() = default;
+BaseVisitor::~BaseVisitor() = default;
+
+bool BaseVisitor::visitLocation(const CXSourceLocation &location) const
+{
+ return clang_Location_isFromMainFile(location) != 0;
+}
+
+BaseVisitor::StartTokenResult BaseVisitor::cbHandleStartToken(const CXCursor &cursor)
+{
+ switch (cursor.kind) {
+ default:
+ break;
+ }
+
+ return startToken(cursor);
+}
+
+bool BaseVisitor::cbHandleEndToken(const CXCursor &cursor, StartTokenResult startResult)
+{
+ const bool result = startResult != Recurse || endToken(cursor);
+ switch (cursor.kind) {
+ default:
+ break;
+ }
+
+ return result;
+}
+
+BaseVisitor::CodeSnippet BaseVisitor::getCodeSnippet(const CXCursor &cursor)
+{
+ CodeSnippet result = m_fileCache.getCodeSnippet(cursor);
+ if (result.first == nullptr)
+ appendDiagnostic(Diagnostic(QStringLiteral("Unable to retrieve code snippet."), cursor, CXDiagnostic_Error));
+ return result;
+}
+
+QString BaseVisitor::getCodeSnippetString(const CXCursor &cursor)
+{
+ CodeSnippet result = m_fileCache.getCodeSnippet(cursor);
+ return result.first != nullptr
+ ? QString::fromUtf8(result.first, int(result.second - result.first))
+ : QString();
+}
+
+static CXChildVisitResult
+ visitorCallback(CXCursor cursor, CXCursor /* parent */, CXClientData clientData)
+{
+ BaseVisitor *bv = reinterpret_cast<BaseVisitor *>(clientData);
+
+ const CXSourceLocation location = clang_getCursorLocation(cursor);
+ if (!bv->visitLocation(location))
+ return CXChildVisit_Continue;
+
+ const BaseVisitor::StartTokenResult startResult = bv->cbHandleStartToken(cursor);
+ switch (startResult) {
+ case clang::BaseVisitor::Error:
+ return CXChildVisit_Break;
+ case clang::BaseVisitor::Skip:
+ break;
+ case clang::BaseVisitor::Recurse:
+ clang_visitChildren(cursor, visitorCallback, clientData);
+ break;
+ }
+
+ if (!bv->cbHandleEndToken(cursor, startResult))
+ return CXChildVisit_Break;
+
+ return CXChildVisit_Continue;
+}
+
+BaseVisitor::Diagnostics BaseVisitor::diagnostics() const
+{
+ return m_diagnostics;
+}
+
+void BaseVisitor::setDiagnostics(const Diagnostics &d)
+{
+ m_diagnostics = d;
+}
+
+void BaseVisitor::appendDiagnostic(const Diagnostic &d)
+{
+ m_diagnostics.append(d);
+}
+
+static inline const char **byteArrayListToFlatArgV(const QByteArrayList &bl)
+{
+ const char **result = new const char *[bl.size() + 1];
+ result[bl.size()] = nullptr;
+ std::transform(bl.cbegin(), bl.cend(), result,
+ [] (const QByteArray &a) { return a.constData(); });
+ return result;
+}
+
+static QByteArray msgCreateTranslationUnit(const QByteArrayList clangArgs, unsigned flags)
+{
+ QByteArray result = "clang_parseTranslationUnit2(0x";
+ result += QByteArray::number(flags, 16);
+ const int count = clangArgs.size();
+ result += ", cmd[" + QByteArray::number(count) + "]=";
+ for (int i = 0; i < count; ++i) {
+ const QByteArray &arg = clangArgs.at(i);
+ if (i)
+ result += ' ';
+ const bool quote = arg.contains(' ') || arg.contains('(');
+ if (quote)
+ result += '"';
+ result += arg;
+ if (quote)
+ result += '"';
+ }
+ result += ')';
+ return result;
+}
+
+static CXTranslationUnit createTranslationUnit(CXIndex index,
+ const QByteArrayList &args,
+ unsigned flags = 0)
+{
+ // courtesy qdoc
+ const unsigned defaultFlags = CXTranslationUnit_SkipFunctionBodies
+ | CXTranslationUnit_Incomplete;
+
+ static const QByteArrayList defaultArgs = {
+ "-std=c++14", // ! otherwise, t.h is parsed as "C"
+ "-fPIC",
+ "-fno-exceptions", // Workaround for clang bug http://reviews.llvm.org/D17988
+#ifdef Q_OS_MACOS
+ "-Wno-expansion-to-defined", // Workaround for warnings in Darwin stdlib, see
+ // https://github.com/darlinghq/darling/issues/204
+#endif
+ "-Wno-constant-logical-operand"
+ };
+
+ const QByteArrayList clangArgs = emulatedCompilerOptions() + defaultArgs + args;
+ QScopedArrayPointer<const char *> argv(byteArrayListToFlatArgV(clangArgs));
+ qDebug().noquote().nospace() << msgCreateTranslationUnit(clangArgs, flags);
+
+ CXTranslationUnit tu;
+ CXErrorCode err = clang_parseTranslationUnit2(index, nullptr, argv.data(),
+ clangArgs.size(), nullptr, 0,
+ defaultFlags | flags, &tu);
+ if (err || !tu) {
+ qWarning().noquote().nospace() << "Could not parse "
+ << clangArgs.constLast().constData() << ", error code: " << err;
+ return nullptr;
+ }
+ return tu;
+}
+
+/* clangFlags are flags to clang_parseTranslationUnit2() such as
+ * CXTranslationUnit_KeepGoing (from CINDEX_VERSION_MAJOR/CINDEX_VERSION_MINOR 0.35)
+ */
+
+bool parse(const QByteArrayList &clangArgs, unsigned clangFlags, BaseVisitor &bv)
+{
+ CXIndex index = clang_createIndex(0 /* excludeDeclarationsFromPCH */,
+ 1 /* displayDiagnostics */);
+ if (!index) {
+ qWarning() << "clang_createIndex() failed!";
+ return false;
+ }
+
+ CXTranslationUnit translationUnit = createTranslationUnit(index, clangArgs, clangFlags);
+ if (!translationUnit)
+ return false;
+
+ CXCursor rootCursor = clang_getTranslationUnitCursor(translationUnit);
+
+ clang_visitChildren(rootCursor, visitorCallback, reinterpret_cast<CXClientData>(&bv));
+
+ QVector<Diagnostic> diagnostics = getDiagnostics(translationUnit);
+ diagnostics.append(bv.diagnostics());
+ bv.setDiagnostics(diagnostics);
+
+ const bool ok = maxSeverity(diagnostics) < CXDiagnostic_Error;
+ if (!ok) {
+ QDebug debug = qWarning();
+ debug.noquote();
+ debug.nospace();
+ debug << "Errors in "
+ << QDir::toNativeSeparators(QFile::decodeName(clangArgs.constLast())) << ":\n";
+ for (const Diagnostic &diagnostic : diagnostics)
+ debug << diagnostic << '\n';
+ }
+
+ clang_disposeTranslationUnit(translationUnit);
+ clang_disposeIndex(index);
+ return ok;
+}
+
+} // namespace clang
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangparser.h b/sources/shiboken2/ApiExtractor/clangparser/clangparser.h
new file mode 100644
index 000000000..ef1424f17
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangparser.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLANGPARSER_H
+#define CLANGPARSER_H
+
+#include <clang-c/Index.h>
+
+#include <QtCore/QByteArrayList>
+#include <QtCore/QHash>
+#include <QtCore/QPair>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+namespace clang {
+
+struct Diagnostic;
+
+class SourceFileCache {
+public:
+ typedef QPair<const char *, const char *> Snippet;
+
+ Snippet getCodeSnippet(const CXCursor &cursor);
+
+private:
+ typedef QHash<QString, QByteArray> FileBufferCache;
+
+ FileBufferCache m_fileBufferCache;
+};
+
+class BaseVisitor {
+ Q_DISABLE_COPY(BaseVisitor)
+public:
+ typedef QVector<Diagnostic> Diagnostics;
+ typedef SourceFileCache::Snippet CodeSnippet;
+
+ enum StartTokenResult { Error, Skip, Recurse };
+
+ BaseVisitor();
+ virtual ~BaseVisitor();
+
+ // Whether location should be visited.
+ // defaults to clang_Location_isFromMainFile()
+ virtual bool visitLocation(const CXSourceLocation &location) const;
+
+ virtual StartTokenResult startToken(const CXCursor &cursor) = 0;
+ virtual bool endToken(const CXCursor &cursor) = 0;
+
+ StartTokenResult cbHandleStartToken(const CXCursor &cursor);
+ bool cbHandleEndToken(const CXCursor &cursor, StartTokenResult startResult);
+
+ CodeSnippet getCodeSnippet(const CXCursor &cursor);
+ QString getCodeSnippetString(const CXCursor &cursor);
+
+ Diagnostics diagnostics() const;
+ void setDiagnostics(const Diagnostics &d);
+ void appendDiagnostic(const Diagnostic &d);
+
+private:
+ SourceFileCache m_fileCache;
+ Diagnostics m_diagnostics;
+};
+
+bool parse(const QByteArrayList &clangArgs, unsigned clangFlags, BaseVisitor &ctx);
+
+} // namespace clang
+
+#endif // !CLANGPARSER_H
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
new file mode 100644
index 000000000..fdc8d3312
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.cpp
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "clangutils.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QHashFunctions>
+#include <QtCore/QProcess>
+
+bool operator==(const CXCursor &c1, const CXCursor &c2)
+{
+ return c1.kind == c2.kind
+ && c1.xdata == c2.xdata
+ && std::equal(c1.data, c1.data + sizeof(c1.data) / sizeof(c1.data[0]), c2.data);
+}
+
+uint qHash(const CXCursor &c, uint seed)
+{
+ return qHash(c.kind) ^ qHash(c.xdata) ^ qHash(c.data[0])
+ ^ qHash(c.data[1]) ^ qHash(c.data[2]) ^ seed;
+}
+
+namespace clang {
+
+SourceLocation getExpansionLocation(const CXSourceLocation &location)
+{
+ SourceLocation result;
+ CXFile file; // void *
+ clang_getExpansionLocation(location, &file, &result.line, &result.column, &result.offset);
+ const CXString cxFileName = clang_getFileName(file);
+ // Has been observed to be 0 for invalid locations
+ if (const char *cFileName = clang_getCString(cxFileName))
+ result.file = QString::fromUtf8(cFileName);
+ clang_disposeString(cxFileName);
+ return result;
+}
+
+SourceLocation getCursorLocation(const CXCursor &cursor)
+{
+ const CXSourceRange extent = clang_getCursorExtent(cursor);
+ return getExpansionLocation(clang_getRangeStart(extent));
+}
+
+CXString getFileNameFromLocation(const CXSourceLocation &location)
+{
+ CXFile file;
+ unsigned line;
+ unsigned column;
+ unsigned offset;
+ clang_getExpansionLocation(location, &file, &line, &column, &offset);
+ return clang_getFileName(file);
+}
+
+SourceRange getCursorRange(const CXCursor &cursor)
+{
+ const CXSourceRange extent = clang_getCursorExtent(cursor);
+ return qMakePair(getExpansionLocation(clang_getRangeStart(extent)),
+ getExpansionLocation(clang_getRangeEnd(extent)));
+}
+
+QString getCursorKindName(CXCursorKind cursorKind)
+{
+ CXString kindName = clang_getCursorKindSpelling(cursorKind);
+ const QString result = QString::fromUtf8(clang_getCString(kindName));
+ clang_disposeString(kindName);
+ return result;
+}
+
+QString getCursorSpelling(const CXCursor &cursor)
+{
+ CXString cursorSpelling = clang_getCursorSpelling(cursor);
+ const QString result = QString::fromUtf8(clang_getCString(cursorSpelling));
+ clang_disposeString(cursorSpelling);
+ return result;
+}
+
+QString getCursorDisplayName(const CXCursor &cursor)
+{
+ CXString displayName = clang_getCursorDisplayName(cursor);
+ const QString result = QString::fromUtf8(clang_getCString(displayName));
+ clang_disposeString(displayName);
+ return result;
+}
+
+QString getTypeName(const CXType &type)
+{
+ CXString typeSpelling = clang_getTypeSpelling(type);
+ const QString result = QString::fromUtf8(clang_getCString(typeSpelling));
+ clang_disposeString(typeSpelling);
+ return result;
+}
+
+Diagnostic::Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s)
+ : message(m), location(getCursorLocation(c)), source(Other), severity(s)
+{
+}
+
+Diagnostic Diagnostic::fromCXDiagnostic(CXDiagnostic cd)
+{
+ Diagnostic result;
+ result.source = Clang;
+ CXString spelling = clang_getDiagnosticSpelling(cd);
+ result.message = QString::fromUtf8(clang_getCString(spelling));
+ clang_disposeString(spelling);
+ result.severity = clang_getDiagnosticSeverity(cd);
+ result.location = getExpansionLocation(clang_getDiagnosticLocation(cd));
+
+ CXDiagnosticSet childDiagnostics = clang_getChildDiagnostics(cd);
+ if (const unsigned childCount = clang_getNumDiagnosticsInSet(childDiagnostics)) {
+ result.childMessages.reserve(int(childCount));
+ const unsigned format = clang_defaultDiagnosticDisplayOptions();
+ for (unsigned i = 0; i < childCount; ++i) {
+ CXDiagnostic childDiagnostic = clang_getDiagnosticInSet(childDiagnostics, i);
+ CXString cdm = clang_formatDiagnostic(childDiagnostic, format);
+ result.childMessages.append(QString::fromUtf8(clang_getCString(cdm)));
+ clang_disposeString(cdm);
+ clang_disposeDiagnostic(childDiagnostic);
+ }
+ }
+
+ return result;
+}
+
+QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu)
+{
+ QVector<Diagnostic> result;
+ const unsigned count = clang_getNumDiagnostics(tu);
+ result.reserve(int(count));
+ for (unsigned i = 0; i < count; ++i) {
+ const CXDiagnostic d = clang_getDiagnostic(tu, i);
+ result.append(Diagnostic::fromCXDiagnostic(d));
+ clang_disposeDiagnostic(d);
+ }
+ return result;
+}
+
+CXDiagnosticSeverity maxSeverity(const QVector<Diagnostic> &ds)
+{
+ CXDiagnosticSeverity result = CXDiagnostic_Ignored;
+ for (const Diagnostic d : ds) {
+ if (d.severity > result)
+ result = d.severity;
+ }
+ return result;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+
+QDebug operator<<(QDebug s, const SourceLocation &l)
+{
+ QDebugStateSaver saver(s);
+ s.nospace();
+ s.noquote();
+ s << QDir::toNativeSeparators(l.file) << ':' << l.line;
+ if (l.column)
+ s << ':' << l.column;
+ return s;
+}
+
+// Roughly follow g++ format:
+// file.cpp:214:37: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
+QDebug operator<<(QDebug s, const Diagnostic &d)
+{
+ QDebugStateSaver saver(s);
+ s.nospace();
+ s.noquote();
+ s << d.location << ": ";
+ switch (d.severity) {
+ case CXDiagnostic_Ignored:
+ s << "ignored";
+ break;
+ case CXDiagnostic_Note:
+ s << "note";
+ break;
+ case CXDiagnostic_Warning:
+ s << "warning";
+ break;
+ case CXDiagnostic_Error:
+ s << "error";
+ break;
+ case CXDiagnostic_Fatal:
+ s << "fatal";
+ break;
+ }
+ s << ": " << d.message;
+
+ if (d.source != Diagnostic::Clang)
+ s << " [other]";
+
+ if (const int childMessagesCount = d.childMessages.size()) {
+ s << '\n';
+ for (int i = 0; i < childMessagesCount; ++i)
+ s << " " << d.childMessages.at(i) << '\n';
+ }
+
+ return s;
+}
+
+#endif // QT_NO_DEBUG_STREAM
+
+} // namespace clang
diff --git a/sources/shiboken2/ApiExtractor/clangparser/clangutils.h b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
new file mode 100644
index 000000000..3437f51eb
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/clangutils.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CLANGUTILS_H
+#define CLANGUTILS_H
+
+#include <clang-c/Index.h>
+#include <QtCore/QPair>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+bool operator==(const CXCursor &c1, const CXCursor &c2);
+uint qHash(const CXCursor &c, uint seed = 0);
+
+namespace clang {
+
+QString getCursorKindName(CXCursorKind cursorKind);
+QString getCursorSpelling(const CXCursor &cursor);
+QString getCursorDisplayName(const CXCursor &cursor);
+QString getTypeName(const CXType &type);
+inline QString getCursorTypeName(const CXCursor &cursor)
+ { return getTypeName(clang_getCursorType(cursor)); }
+inline QString getCursorResultTypeName(const CXCursor &cursor)
+ { return getTypeName(clang_getCursorResultType(cursor)); }
+
+inline bool isCursorValid(const CXCursor &c)
+{
+ return c.kind < CXCursor_FirstInvalid || c.kind > CXCursor_LastInvalid;
+}
+
+struct SourceLocation
+{
+ int compare(const SourceLocation &rhs) const;
+
+ QString file;
+ unsigned line = 0;
+ unsigned column = 0;
+ unsigned offset = 0;
+};
+
+SourceLocation getExpansionLocation(const CXSourceLocation &location);
+
+typedef QPair<SourceLocation, SourceLocation> SourceRange;
+
+SourceLocation getCursorLocation(const CXCursor &cursor);
+CXString getFileNameFromLocation(const CXSourceLocation &location);
+SourceRange getCursorRange(const CXCursor &cursor);
+
+struct Diagnostic {
+ enum Source { Clang, Other };
+
+ Diagnostic() : source(Clang) {}
+ // Clang
+ static Diagnostic fromCXDiagnostic(CXDiagnostic cd);
+ // Other
+ explicit Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s = CXDiagnostic_Warning);
+
+ QString message;
+ QStringList childMessages;
+ SourceLocation location;
+ Source source;
+ CXDiagnosticSeverity severity;
+};
+
+QVector<Diagnostic> getDiagnostics(CXTranslationUnit tu);
+CXDiagnosticSeverity maxSeverity(const QVector<Diagnostic> &ds);
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug, const SourceLocation &);
+QDebug operator<<(QDebug, const Diagnostic &);
+#endif // QT_NO_DEBUG_STREAM
+} // namespace clang
+
+#endif // CLANGUTILS_H
diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp
new file mode 100644
index 000000000..df82f9080
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "compilersupport.h"
+#include "header_paths.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QProcess>
+#include <QtCore/QStringList>
+
+#include <string.h>
+#include <algorithm>
+#include <iterator>
+
+namespace clang {
+
+static bool runProcess(const QString &program, const QStringList &arguments,
+ QByteArray *stdOutIn = nullptr, QByteArray *stdErrIn = nullptr)
+{
+ QProcess process;
+ process.start(program, arguments, QProcess::ReadWrite);
+ if (!process.waitForStarted()) {
+ qWarning().noquote().nospace() << "Unable to start "
+ << process.program() << ": " << process.errorString();
+ return false;
+ }
+ process.closeWriteChannel();
+ const bool finished = process.waitForFinished();
+ const QByteArray stdErr = process.readAllStandardError();
+ if (stdErrIn)
+ *stdErrIn = stdErr;
+ if (stdOutIn)
+ *stdOutIn = process.readAllStandardOutput();
+
+ if (!finished) {
+ qWarning().noquote().nospace() << process.program() << " timed out: " << stdErr;
+ process.kill();
+ return false;
+ }
+
+ if (process.exitStatus() != QProcess::NormalExit) {
+ qWarning().noquote().nospace() << process.program() << " crashed: " << stdErr;
+ return false;
+ }
+
+ if (process.exitCode() != 0) {
+ qWarning().noquote().nospace() << process.program() << " exited "
+ << process.exitCode() << ": " << stdErr;
+ return false;
+ }
+
+ return true;
+}
+
+#if defined(Q_CC_GNU)
+
+static QByteArray frameworkPath() { return QByteArrayLiteral(" (framework directory)"); }
+
+// Determine g++'s internal include paths from the output of
+// g++ -E -x c++ - -v </dev/null
+// Output looks like:
+// #include <...> search starts here:
+// /usr/local/include
+// /System/Library/Frameworks (framework directory)
+// End of search list.
+static HeaderPaths gppInternalIncludePaths(const QString &compiler)
+{
+ HeaderPaths result;
+ QStringList arguments;
+ arguments << QStringLiteral("-E") << QStringLiteral("-x") << QStringLiteral("c++")
+ << QStringLiteral("-") << QStringLiteral("-v");
+ QByteArray stdOut;
+ QByteArray stdErr;
+ if (!runProcess(compiler, arguments, &stdOut, &stdErr))
+ return result;
+ const QByteArrayList stdErrLines = stdErr.split('\n');
+ bool isIncludeDir = false;
+ for (const QByteArray &line : stdErrLines) {
+ if (isIncludeDir) {
+ if (line.startsWith(QByteArrayLiteral("End of search list"))) {
+ isIncludeDir = false;
+ } else {
+ HeaderPath headerPath(line.trimmed());
+ if (headerPath.path.endsWith(frameworkPath())) {
+ headerPath.m_isFramework = true;
+ headerPath.path.truncate(headerPath.path.size() - frameworkPath().size());
+ }
+ result.append(headerPath);
+ }
+ } else if (line.startsWith(QByteArrayLiteral("#include <...> search starts here"))) {
+ isIncludeDir = true;
+ }
+ }
+ return result;
+}
+#endif // Q_CC_MSVC
+
+// For MSVC, we set the MS compatibility version and let Clang figure out its own
+// options and include paths.
+// For the others, we pass "-nostdinc" since libclang tries to add it's own system
+// include paths, which together with the clang compiler paths causes some clash
+// which causes std types not being found and construct -I/-F options from the
+// include paths of the host compiler.
+
+static QByteArray noStandardIncludeOption() { return QByteArrayLiteral("-nostdinc"); }
+
+// Returns clang options needed for emulating the host compiler
+QByteArrayList emulatedCompilerOptions()
+{
+ QByteArrayList result;
+#if defined(Q_CC_MSVC)
+ const HeaderPaths headerPaths;
+ result.append(QByteArrayLiteral("-fms-compatibility-version=19"));
+#elif defined(Q_CC_CLANG)
+ const HeaderPaths headerPaths = gppInternalIncludePaths(QStringLiteral("clang++"));
+ result.append(noStandardIncludeOption());
+#elif defined(Q_CC_GNU)
+ const HeaderPaths headerPaths = gppInternalIncludePaths(QStringLiteral("g++"));
+ result.append(noStandardIncludeOption());
+#else
+ const HeaderPaths headerPaths;
+#endif
+ std::transform(headerPaths.cbegin(), headerPaths.cend(),
+ std::back_inserter(result), [](const HeaderPath &p) {
+ return HeaderPath::includeOption(p, true);
+ });
+ return result;
+}
+
+} // namespace clang
diff --git a/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h
new file mode 100644
index 000000000..f556da551
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/clangparser/compilersupport.h
@@ -0,0 +1,40 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef COMPILERSUPPORT_H
+#define COMPILERSUPPORT_H
+
+#include <QtCore/QByteArrayList>
+
+namespace clang {
+
+QByteArrayList emulatedCompilerOptions();
+
+} // namespace clang
+
+#endif // COMPILERSUPPORT_H
diff --git a/sources/shiboken2/ApiExtractor/cmake_uninstall.cmake b/sources/shiboken2/ApiExtractor/cmake_uninstall.cmake
new file mode 100644
index 000000000..df95fb9d8
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/cmake_uninstall.cmake
@@ -0,0 +1,21 @@
+IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+ MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
+ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+
+FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+STRING(REGEX REPLACE "\n" ";" files "${files}")
+FOREACH(file ${files})
+ MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
+ IF(EXISTS "$ENV{DESTDIR}${file}")
+ EXEC_PROGRAM(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ IF(NOT "${rm_retval}" STREQUAL 0)
+ MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
+ ENDIF(NOT "${rm_retval}" STREQUAL 0)
+ ELSE(EXISTS "$ENV{DESTDIR}${file}")
+ MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
+ ENDIF(EXISTS "$ENV{DESTDIR}${file}")
+ENDFOREACH(file)
diff --git a/sources/shiboken2/ApiExtractor/dependency.h b/sources/shiboken2/ApiExtractor/dependency.h
new file mode 100644
index 000000000..17fbffcce
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/dependency.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEPENDENCY_H
+#define DEPENDENCY_H
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+// Dependencies for topologically sorting classes
+struct Dependency {
+ QString parent;
+ QString child;
+};
+
+typedef QVector<Dependency> Dependencies;
+
+#endif // DEPENDENCY_H
diff --git a/sources/shiboken2/ApiExtractor/doc/CMakeLists.txt b/sources/shiboken2/ApiExtractor/doc/CMakeLists.txt
new file mode 100644
index 000000000..d78844dc8
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/CMakeLists.txt
@@ -0,0 +1,10 @@
+
+find_program(SPHINX sphinx-build DOC "Path to sphinx-build binary.")
+
+if (SPHINX)
+ message("-- sphinx-build - found")
+ configure_file(conf.py.in conf.py @ONLY)
+ add_custom_target(doc ${SPHINX} -b html -c . ${CMAKE_CURRENT_SOURCE_DIR} html )
+else()
+ message("-- sphinx-build - not found! doc target disabled")
+endif() \ No newline at end of file
diff --git a/sources/shiboken2/ApiExtractor/doc/_templates/index.html b/sources/shiboken2/ApiExtractor/doc/_templates/index.html
new file mode 100644
index 000000000..4aa14ede5
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_templates/index.html
@@ -0,0 +1,27 @@
+{% extends "layout.html" %}
+{% set title = 'Overview' %}
+{% block body %}
+<div class="section">
+ <h1>API Extractor {{ version }}</h1>
+
+ <p>API Extractor is a tool that eases the development of bindings of Qt-based libraries for high
+ level languages by automating most of the process.
+
+ <p>API Extractor is based on the
+ <a href="http://labs.trolltech.com/page/Projects/QtScript/Generator">QtScriptGenerator</a> project.</p>
+
+ <h2>Documentation</h2>
+ <table class="contentstable"><tr>
+ <td width="50%">
+ <p class="biglink"><a href="{{ pathto("overview") }}">Overview</a><br/>
+ <span class="linkdescr">how API Extractor works</span></p>
+ <p class="biglink"><a href="{{ pathto("typesystem") }}">Typesystem reference</a><br/>
+ <span class="linkdescr">reference for all typesystem tags</span></p>
+ </td>
+ <td width="50%">
+ <p class="biglink"><a href="{{ pathto("contents") }}">Contents</a><br/>
+ <span class="linkdescr">for a complete overview</span></p>
+ </td></tr>
+ </table>
+</div>
+{% endblock %}
diff --git a/sources/shiboken2/ApiExtractor/doc/_templates/layout.html b/sources/shiboken2/ApiExtractor/doc/_templates/layout.html
new file mode 100644
index 000000000..9dc53722d
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_templates/layout.html
@@ -0,0 +1,41 @@
+{% extends "!layout.html" %}
+
+# Invert sidebars
+{%- block sidebar1 %}{{ sidebar() }}{%- endblock %}
+{%- block sidebar2 %}{%- endblock %}
+
+{%- block header %}
+<div id="container">
+<div class="header">
+ <div class="header_container">
+ <div class="logo"><a href="http://www.pyside.org"><img alt="PySide" src="{{ pathto('_static/pysidelogo.png', 1) }}" width="199" height="102" /></a></div>
+ <div class="related">
+ <ul>
+ {%- block rootrellink %}
+ <li><a href="{{ pathto( 'index' ) }}">{{ shorttitle|e }}</a></li>
+ {%- endblock %}
+ {%- for parent in parents %}
+ <li>{{ reldelim1 }} <a href="{{ parent.link|e }}" {% if loop.last %}{{ accesskey("U") }}{% endif %}>{{ parent.title }}</a></li>
+ {%- endfor %}
+ {%- block relbaritems %} {% endblock %}
+ </ul>
+ </div>
+ </div>
+</div>
+{%- endblock -%}
+
+{%- block footer %}
+ <div class="footer">
+ <a href="http://www.indt.org.br"><img src="{{ pathto('_static/logo_indt.jpg', 1) }}" alt="Indt" border="0" /></a>
+ <a href="http://www.openbossa.org"><img src="{{ pathto('_static/logo_openbossa.png', 1) }}" alt="Openbossa" border="0" /></a>
+ <a href="http://qt.nokia.com/"><img src="{{ pathto('_static/logo_qt.png', 1) }}" alt="Qt" border="0" /></a>
+ <a href="http://www.python.org"><img src="{{ pathto('_static/logo_python.jpg', 1) }}" alt="Python" border="0" /></a>
+ </div>
+</div>
+{%- endblock %}
+
+# No top relbar.
+{%- block relbar1 %}{%- endblock %}
+
+# No bottom relbar.
+{%- block relbar2 %}{%- endblock %}
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/searchbox.html b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/searchbox.html
new file mode 100644
index 000000000..55a972156
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/searchbox.html
@@ -0,0 +1,12 @@
+{%- if pagename != "search" %}
+<div id="searchbox" style="display: none">
+ <h3>{{ _('Quick search') }}</h3>
+ <form class="search" action="{{ pathto('search') }}" method="get">
+ <input type="text" name="q" id="q" size="18" />
+ <input type="submit" value="{{ _('Go') }}" id="search_button" />
+ <input type="hidden" name="check_keywords" value="yes" />
+ <input type="hidden" name="area" value="default" />
+ </form>
+</div>
+<script type="text/javascript">$('#searchbox').show(0);</script>
+{%- endif %}
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.png
new file mode 100644
index 000000000..843e7e2c5
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.png
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg
new file mode 100644
index 000000000..4229ae8db
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png
new file mode 100644
index 000000000..b45830e00
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg
new file mode 100644
index 000000000..2a1fbe7a1
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png
new file mode 100644
index 000000000..51e868d6e
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg
new file mode 100644
index 000000000..cd474efba
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png
new file mode 100644
index 000000000..37800f454
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidedocs.css b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidedocs.css
new file mode 100644
index 000000000..fd81f4379
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidedocs.css
@@ -0,0 +1,409 @@
+* {
+ font: 100% Verdana, Arial, Helvetica, sans-serif;
+ font-size:12px;
+}
+
+html {
+ height: 100%;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ text-align: center;
+ background-color: #EBEBEB;
+ height: 100%;
+ color: #333;
+}
+
+strong {
+ font-weight:bold;
+}
+
+.document {
+ padding-bottom: 90px;
+}
+
+#container {
+ position: relative;
+ min-height: 100%;
+ background-image: url(fakebar.png);
+ background-repeat: repeat-y;
+ background-color: white;
+}
+
+.footer {
+ position: absolute;
+ bottom: 0px;
+ margin-top: 50px;
+ text-align:center;
+ background-color: white;
+ border-top: 2px solid #e0e0e0;
+ white-space: nowrap;
+ height: 90px;
+ width: 100%;
+}
+
+.footer img {
+ margin-left: 8px;
+ margin-right: 8px;
+}
+
+.sphinxsidebar {
+ float: left;
+ width: 250px;
+ padding: 0px 10px 0px 10px;
+ text-align: left;
+}
+
+.sphinxsidebar ul {
+ padding: 0px;
+ margin: 0px;
+ list-style-position: inside;
+}
+
+.sphinxsidebar > ul {
+ padding: 0px;
+ margin: 0px;
+}
+
+.sphinxsidebar ul li {
+ margin-left: 10px;
+ padding: 0px;
+}
+
+.sphinxsidebar h3, .sphinxsidebar h3 a {
+ font-weight: bold;
+ color: #333;
+}
+
+.documentwrapper {
+ margin-left: 270px;
+ text-align: left;
+ background-color: #ffffff;
+ border-left: 1px solid #989898;
+ font-size:18px;
+ padding: 10px 50px 15px 50px;
+ height: 100%;
+}
+
+h1 {
+ font-size:18px;
+ padding-left: 50px;
+ padding-bottom: 15px;
+ padding-top: 15px;
+ border-bottom: 1px solid #c2c2c2;
+ text-transform:uppercase;
+ margin-right: -100px;
+ position: relative;
+ left: -50px;
+ top: -10px;
+}
+
+h2 {
+ font-size:12px;
+ font-weight:bold;
+ border-left-width: 1px;
+ border-right-width: 1px;
+ border-top-width: 1px;
+ border-bottom-width: 2px;
+ border-style: solid;
+ border-left-color: #b1b1b1;
+ border-right-color: #b1b1b1;
+ border-top-color: #b1b1b1;
+ border-bottom-color: #009491;
+ background-color: #e0e0e0;
+ padding:5px;
+ margin-top: 20px;
+ -moz-border-radius:5px;
+ -webkit-border-radius:5px;
+ -khtml-border-radius:5px;
+}
+
+h3, h4 {
+ font-weight: bolder;
+}
+
+pre {
+ border-top: 1px solid #e0e0e0;
+ border-bottom: 1px solid #e0e0e0;
+ background-color: #fafafa;
+ padding: 5px;
+ font: 100% monospace;
+ overflow: auto;
+}
+
+pre * {
+ font: 100% monospace;
+}
+
+.headerlink {
+ font-size: 100%;
+ color: inherit;
+ float: right;
+ visibility: Hidden;
+}
+
+h1 .headerlink {
+ padding-right: 50px;
+}
+
+h1:hover .headerlink, h2:hover .headerlink, h3:hover .headerlink {
+ visibility: Visible;
+}
+
+a, a:visited {
+ color: #009491;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+div.warning {
+ background-color: #ffe4e4;
+ border: 1px solid #f66;
+}
+
+div.note {
+ border: 1px solid #e3e3e3;
+}
+
+table.docutils {
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 10px;
+ border: none;
+}
+
+table.docutils td {
+ border: none;
+}
+
+table.docutils th {
+ border: none;
+ font-weight: bold;
+ vertical-align: top;
+}
+
+h2 em {
+ float: right;
+ font-size: 10px;
+ position: relative;
+ top: -20px;
+}
+
+/* Table of pymaemo components */
+
+#development table.docutils td {
+ border-bottom: 1px solid #EBEBEB;
+}
+
+#development th {
+ background-color: #EBEBEB;
+ color: #FC7E00;
+ padding: 5px;
+}
+
+#development th:first-child {
+ -moz-border-radius: 20px 0px 0px 0px;
+ -webkit-border-radius: 20px 0px 0px 0px;
+ -khtml-border-radius: 20px 0px 0px 0px;
+ padding-left: 10px;
+}
+#development th:last-child {
+ -moz-border-radius: 0px 20px 0px 0px;
+ -webkit-border-radius: 0px 20px 0px 0px;
+ -khtml-border-radius: 0px 20px 0px 0px;
+ padding-right: 10px;
+ width: 100px;
+}
+
+hr {
+ border: none;
+ border-bottom: 1px dashed #EBEBEB;
+ width: 70%
+}
+
+.oldnews {
+ text-align: right;
+}
+
+/******************* TOPO *****************************/
+.header {
+ background-image: url(bg_topo.jpg);
+ background-repeat: repeat-x;
+ height: 147px;
+}
+
+.header_container {
+ background-image: url(bg_header.png);
+ background-repeat: no-repeat;
+ background-position: 100px 0px;
+}
+
+.logo {
+ text-align: left;
+ margin-bottom: 10px;
+}
+
+#searchbox {
+ border-top: 1px solid #989898;
+ padding-top: 10px;
+ margin-left: -10px;
+ margin-right: -10px;
+ padding-left: 10px;
+ padding-right: 10px;
+}
+
+#search_button {
+ border: 1px solid #3A393A;
+ background-color: #3A393A;
+ color: white;
+ cursor: pointer;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -khtml-border-radius: 5px;
+
+}
+
+form {
+ margin: 0px;
+ padding: 0px;
+}
+
+/* search field */
+form #q {
+ width: 136px;
+/* height: 22px; */
+ border: none;
+ margin: 0px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -khtml-border-radius: 5px;
+ margin-top: 2px;
+ padding: 4px;
+ line-height: 22px
+}
+
+#search-results h2 {
+ display: none;
+}
+
+#search-results h2 {
+ display: none;
+}
+
+#search-results ul.search {
+ margin: 0px;
+ padding: 0px;
+}
+
+ul.search div.context {
+ padding-left: 40px;
+}
+
+#installation td {
+ text-align: center;
+ font-weight: bold;
+}
+
+em {
+ color: inherit;
+ font-style:italic;
+}
+
+/******** REL bar *********/
+
+.related {
+ display: inline;
+}
+
+.related ul {
+ padding: 0px 0px 0px 10px;
+ margin: 0px;
+ text-align: left;
+ background-image: url(relbar_bg.png);
+}
+
+.related li {
+ display: inline;
+ color: white;
+ font-weight: bold;
+}
+
+.related li a {
+ color: inherit;
+ line-height: 35px;
+ font-weight: bold;
+ vertical-align: middle;
+}
+
+.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+.related h3 {
+ display: none;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.contentstable {
+ width: 100%;
+}
+
+.contentstable td {
+ padding-left: 30px;
+ vertical-align: top;
+}
+
+p.biglink a {
+ font-size: 20px;
+}
+
+dt:target, .highlight {
+ background-color: #fbe54e;
+}
+
+img {
+ border: 0px;
+}
+
+.figure .caption {
+ font-style:italic;
+}
+
+table.footnote {
+ margin: 0px;
+}
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.png
new file mode 100644
index 000000000..076c1057c
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.png
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png
new file mode 100644
index 000000000..4036733a7
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png
Binary files differ
diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/theme.conf b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/theme.conf
new file mode 100644
index 000000000..e0a652a5d
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/theme.conf
@@ -0,0 +1,7 @@
+[theme]
+inherit = default
+stylesheet = pysidedocs.css
+pygments_style = none
+
+[options]
+nosidebar = false
diff --git a/sources/shiboken2/ApiExtractor/doc/conf.py.in b/sources/shiboken2/ApiExtractor/doc/conf.py.in
new file mode 100644
index 000000000..70750c899
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/conf.py.in
@@ -0,0 +1,163 @@
+# -*- coding: utf-8 -*-
+#
+# ApiExtractor documentation build configuration file, created by
+# sphinx-quickstart on Wed Apr 22 15:04:20 2009.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.append(os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# 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']
+
+rst_epilog = """
+.. |project| replace:: API Extractor
+"""
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+source_encoding = 'utf-8'
+
+# The master toctree document.
+#master_doc = 'contents'
+
+# General information about the project.
+project = u'API Extractor'
+copyright = u'2009-2010, Nokia Corporation'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '@apiextractor_MAJOR_VERSION@.@apiextractor_MINOR_VERSION@'
+# The full version, including alpha/beta/rc tags.
+release = '@apiextractor_VERSION@'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directory, that shouldn't be searched
+# for source files.
+exclude_trees = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. Major themes that come with
+# Sphinx are currently 'default' and 'sphinxdoc'.
+html_theme = 'pysidedocs'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {
+#}
+
+# Add any paths that contain custom themes here, relative to this directory.
+html_theme_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_themes']
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+#html_static_path = ['@CMAKE_CURRENT_SOURCE_DIR@/_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = { '' : ''}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+html_additional_pages = { 'index' : 'index.html'}
+
+# If false, no index is generated.
+html_use_index = False
+
+# If true, the index is split into individual pages for each letter.
+html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+html_show_sourcelink = False
+
+html_add_permalinks = True;
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
diff --git a/sources/shiboken2/ApiExtractor/doc/contents.rst b/sources/shiboken2/ApiExtractor/doc/contents.rst
new file mode 100644
index 000000000..83a4889fe
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/contents.rst
@@ -0,0 +1,9 @@
+Table of contents
+*****************
+.. toctree::
+ :numbered:
+ :maxdepth: 3
+
+ overview.rst
+ ownership.rst
+ typesystem.rst
diff --git a/sources/shiboken2/ApiExtractor/doc/dependency-apiextractor.svg b/sources/shiboken2/ApiExtractor/doc/dependency-apiextractor.svg
new file mode 100644
index 000000000..6bec8b5a8
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/dependency-apiextractor.svg
@@ -0,0 +1,360 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="750"
+ height="230"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ version="1.0"
+ sodipodi:docname="dependency-apiextractor.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:export-filename="/tmp/dependency-pyside.png"
+ inkscape:export-xdpi="90"
+ inkscape:export-ydpi="90">
+ <defs
+ id="defs4">
+ <marker
+ inkscape:stockid="Arrow1Lstart"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lstart"
+ style="overflow:visible">
+ <path
+ id="path3270"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(0.8,0,0,0.8,10,0)" />
+ </marker>
+ <marker
+ inkscape:stockid="Arrow1Lend"
+ orient="auto"
+ refY="0"
+ refX="0"
+ id="Arrow1Lend"
+ style="overflow:visible">
+ <path
+ id="path3679"
+ d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z"
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none"
+ transform="matrix(-0.8,0,0,-0.8,-10,0)" />
+ </marker>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.6315754"
+ inkscape:cx="375"
+ inkscape:cy="115"
+ inkscape:document-units="px"
+ inkscape:current-layer="svg2"
+ showgrid="false"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ inkscape:window-width="1278"
+ inkscape:window-height="949"
+ inkscape:window-x="1330"
+ inkscape:window-y="25">
+ <sodipodi:guide
+ orientation="1,0"
+ position="384.28571,590"
+ id="guide2601" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="678.57143,491.42857"
+ id="guide2603" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="78.571429,257.14286"
+ id="guide2605" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="93.571429,280.71429"
+ id="guide7565" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="148.57143,216.42857"
+ id="guide7567" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-250.44576,-308.53365)" />
+ <g
+ id="g2664"
+ transform="translate(-162.03535,-115.53321)">
+ <path
+ inkscape:connector-type="polyline"
+ id="path2869"
+ d="M 439.27375,270.21407 L 594.99083,193.03351"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <g
+ transform="translate(166.24286,-190.07976)"
+ id="g2606">
+ <rect
+ style="fill:#e3e2db;stroke:#000000;stroke-opacity:1"
+ id="rect7541"
+ width="211.42857"
+ height="124.28571"
+ x="6.6142678"
+ y="308.16089"
+ ry="17.142857" />
+ <text
+ xml:space="preserve"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="76.614265"
+ y="339.74512"
+ id="text7543"><tspan
+ sodipodi:role="line"
+ id="tspan7545"
+ x="76.614265"
+ y="339.74512">Boost</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="76.614265"
+ y="372.67505"
+ id="text7547"><tspan
+ sodipodi:role="line"
+ id="tspan7549"
+ x="76.614265"
+ y="372.67505">Qt Software</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="76.614265"
+ y="408.38055"
+ id="text7551"><tspan
+ sodipodi:role="line"
+ id="tspan7553"
+ x="76.614265"
+ y="408.38055">INdT/Nokia</tspan></text>
+ <rect
+ style="fill:#aaeeff;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1"
+ id="rect7555"
+ width="43.163269"
+ height="22.5"
+ x="21.614267"
+ y="321.55374"
+ ry="6.4285707" />
+ <rect
+ style="fill:#b3ff80;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1"
+ id="rect7561"
+ width="43.163269"
+ height="22.5"
+ x="21.614267"
+ y="355.4823"
+ ry="6.4285707" />
+ <rect
+ style="fill:#e9ddaf;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1"
+ id="rect7563"
+ width="43.163269"
+ height="22.5"
+ x="21.614267"
+ y="390.4823"
+ ry="6.4285707" />
+ </g>
+ <path
+ inkscape:connector-type="polyline"
+ id="path2604"
+ d="M 782.79015,270.0418 L 627.07307,192.86124"
+ style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" />
+ <g
+ transform="translate(234.84929,-73.143707)"
+ id="g5193">
+ <rect
+ ry="9.2689295"
+ style="fill:#b3ff80;fill-rule:evenodd;stroke:#2a7800;stroke-width:0.96558368px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2417"
+ width="274.18781"
+ height="73.282379"
+ x="78.571426"
+ y="342.86383"
+ rx="8.3239012" />
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="88.822823"
+ y="359.67014"
+ id="text2419"><tspan
+ sodipodi:role="line"
+ id="tspan2421"
+ x="88.822823"
+ y="359.67014">Qt 4.5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="88.822823"
+ y="375.33484"
+ id="text2423"><tspan
+ sodipodi:role="line"
+ id="tspan2425"
+ x="88.822823"
+ y="375.33484">4.5</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="88.822823"
+ y="390.87479"
+ id="text2427"><tspan
+ sodipodi:role="line"
+ id="tspan2429"
+ x="88.822823"
+ y="390.87479">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="88.822823"
+ y="400.84058"
+ id="text2431"><tspan
+ sodipodi:role="line"
+ id="tspan2433"
+ x="88.822823"
+ y="400.84058">GNU General Public License v3 /</tspan><tspan
+ id="tspan2472"
+ sodipodi:role="line"
+ x="88.822823"
+ y="411.1687">GNU Lesser General Public Licence v2.1</tspan></text>
+ </g>
+ <g
+ transform="translate(101.41581,-378.37135)"
+ id="g5120">
+ <rect
+ rx="10.404889"
+ ry="13.104635"
+ style="fill:#e9ddaf;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2441"
+ width="274.54263"
+ height="73.281754"
+ x="384.28571"
+ y="496.43558" />
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="513.59869"
+ id="text2443"><tspan
+ sodipodi:role="line"
+ id="tspan2445"
+ x="389.17969"
+ y="513.59869">libapiextractor</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="529.26337"
+ id="text2447"><tspan
+ sodipodi:role="line"
+ id="tspan2449"
+ x="389.17969"
+ y="529.26337">0.2</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="544.80334"
+ id="text2451"><tspan
+ sodipodi:role="line"
+ x="389.17969"
+ y="544.80334"
+ id="tspan2453">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="560.12628"
+ id="text2455"><tspan
+ sodipodi:role="line"
+ id="tspan2457"
+ x="389.17969"
+ y="560.12628">LGPL version 2.1</tspan></text>
+ </g>
+ <g
+ transform="translate(242.40213,-378.858)"
+ id="g5182">
+ <rect
+ ry="11.287985"
+ style="fill:#aaeeff;fill-rule:evenodd;stroke:#006078;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ id="rect2563"
+ width="274.54263"
+ height="73.281754"
+ x="384.28571"
+ y="648.57843"
+ rx="10.404877" />
+ <text
+ xml:space="preserve"
+ style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="665.74158"
+ id="text2565"><tspan
+ sodipodi:role="line"
+ id="tspan2567"
+ x="389.17969"
+ y="665.74158">boost::graph</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="681.40625"
+ id="text2569"><tspan
+ sodipodi:role="line"
+ id="tspan2571"
+ x="389.17969"
+ y="681.40625">1.38.0</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="696.94623"
+ id="text2573"><tspan
+ sodipodi:role="line"
+ x="389.17969"
+ y="696.94623"
+ id="tspan2575">headers and libraries - compile-time and run-time</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans"
+ x="389.17969"
+ y="712.26917"
+ id="text2577"><tspan
+ sodipodi:role="line"
+ id="tspan2579"
+ x="389.17969"
+ y="712.26917">Boost Software License 1.0</tspan></text>
+ </g>
+ </g>
+</svg>
diff --git a/sources/shiboken2/ApiExtractor/doc/overview.rst b/sources/shiboken2/ApiExtractor/doc/overview.rst
new file mode 100644
index 000000000..471e2439b
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/overview.rst
@@ -0,0 +1,15 @@
+.. _gen-overview:
+
+**********************
+API Extractor Overview
+**********************
+
+The **API Extractor** library is used by the binding generator to parse headers
+of a given library and merge this data with information provided by
+typesystem (XML) files, resulting in a representation of how the API should be
+exported to the chosen target language. The generation of source code for the
+bindings is performed by specific generators using the API Extractor library.
+
+The API Extractor is based on QtScriptGenerator_ codebase.
+
+.. _QtScriptGenerator: http://labs.trolltech.com/page/Projects/QtScript/Generator
diff --git a/sources/shiboken2/ApiExtractor/doc/ownership.rst b/sources/shiboken2/ApiExtractor/doc/ownership.rst
new file mode 100644
index 000000000..760967da6
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/ownership.rst
@@ -0,0 +1,85 @@
+Ownership Management
+********************
+
+Among the various types of instances interactions, sometimes an object
+may be *owned* by another object, so that the owner is responsible for
+destroying the owned object, like in Qt's object system [#]_.
+This kind of relationship has a big role on interfacing with the target language, like
+with Python's reference counting.
+
+
+Ownership transfers
+-------------------
+
+From C++ to target
+^^^^^^^^^^^^^^^^^^
+
+ When an object that is currently owned by C++ has its ownership transfered
+ back to the target language, the binding can know for sure when the object will be deleted and
+ tie the C++ instance existence to the wrapper, calling the C++ destructor normally when the
+ wrapper is deleted.
+
+ .. code-block:: xml
+
+ <modify-argument index="1">
+ <define-ownership class="target" owner="target" />
+ </modify-argument>
+
+
+From target to C++
+^^^^^^^^^^^^^^^^^^
+
+ In the opposite direction,when an object ownership is transfered from the target language
+ to C++, the native code takes full control of the object life and you don't
+ know when that object will be deleted, rendering the wrapper object invalid,
+ unless you're wrapping an object with a virtual destructor,
+ so you can override it and be notified of its destruction.
+
+ By default it's safer to just render the wrapper
+ object invalid and raise some error if the user tries to access
+ one of this objects members or pass it as argument to some function, to avoid unpleasant segfaults.
+ Also you should avoid calling the C++ destructor when deleting the wrapper.
+
+ .. code-block:: xml
+
+ <modify-argument index="1">
+ <define-ownership class="target" owner="c++" />
+ </modify-argument>
+
+
+Parent-child relationship
+-------------------------
+
+One special type of relationship is the parent-child. When an object is called
+the parent of another object (the child), the former is in charge of deleting its
+child when deleted and the target language can trust that the child will be alive
+as long as the parent is, unless some other method can take the C++ ownership away from the parent.
+
+One of the main uses of this scheme is Qt's object system, with ownership among QObject-derived
+classes, creating "trees" of instances.
+
+ .. code-block:: xml
+
+ <modify-argument index="this">
+ <parent index="1" action="add">
+ </modify-argument>
+
+In this example, the instance with the method that is being invoked (indicated by 'index="this"' on
+modify-argument) will be marked as a child
+of the first argument using the `parent` tag. To remove ownership, just use "remove" in the action attribute. **Removing
+parentship also transfers the ownership back to python.**
+
+Invalidation after use
+----------------------
+
+Sometimes an object is created as a virtual method call argument and destroyed after the
+call returned. In this case, you should use the ``invalidate-after-use`` attribute in the
+``modify-argument`` tag to mark the wrapper as invalid right after the virtual method returns.
+
+ .. code-block:: xml
+
+ <modify-argument index="2" invalidate-after-use="yes"/>
+
+In this example the second argument will be invalidated after this method call.
+
+.. [#] See *Object Trees and Object Ownership* http://doc.trolltech.com/4.5/objecttrees.html
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem.rst b/sources/shiboken2/ApiExtractor/doc/typesystem.rst
new file mode 100644
index 000000000..69dda43a0
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem.rst
@@ -0,0 +1,29 @@
+The API Extractor Type System
+*****************************
+
+The typesystem is used by a binding generator or any other software using the APIExtractor library
+to map a C++ library API onto a higher level language.
+
+The typesystem specification is a handwritten XML document listing the types
+that will be available in the generated target language API; types that are not
+declared in the specification will be ignored along with everything depending on
+them. In addition, it is possible to manipulate and modify types and functions.
+It is even possible to use the typesystem specification to inject arbitrary
+code into the source files, such as an extra member function.
+
+Below there is a complete reference guide to the various nodes (XML tags) of the typesystem.
+For usage examples, take a look at the typesystem files used to generate PySide. These files
+can be found in the PySide/<QT_MODULE_NAME> directory of the PySide package.
+
+.. toctree::
+
+ typesystem_specifying_types
+ typesystem_manipulating_objects
+ typesystem_modify_function
+ typesystem_arguments
+ typesystem_solving_compilation
+ typesystem_templates
+ typesystem_conversionrule
+ typesystem_documentation
+
+
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_arguments.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_arguments.rst
new file mode 100644
index 000000000..16e0678d3
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_arguments.rst
@@ -0,0 +1,192 @@
+.. _modifying-arguments:
+
+Modifying Arguments
+-------------------
+
+.. _conversion-rule:
+
+conversion-rule
+^^^^^^^^^^^^^^^
+
+ The conversion-rule node allows you to write customized code to convert
+ the given argument between the target language and C++, and it is a child of the modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument ...>
+ <conversion-rule class="target | native">
+ // the code
+ </conversion-rule>
+ </modify-argument>
+
+ This node is typically used in combination with the replace-type and
+ remove-argument nodes. The given code is used instead of the generator's
+ conversion code.
+
+ Writing %N in the code (where N is a number), will insert the name of the
+ nth argument. Alternatively, %in and %out which will be replaced with the
+ name of the conversion's input and output variable, respectively. Note the
+ output variable must be declared explicitly, for example:
+
+ .. code-block:: xml
+
+ <conversion-rule class="native">
+ bool %out = (bool) %in;
+ </conversion-rule>
+
+ .. note:: You can also use the conversion-rule node to specify :ref:`a conversion code which will be used instead of the generator's conversion code everywhere for a given type <conversion-rule-on-types>`.
+
+remove-argument
+^^^^^^^^^^^^^^^
+
+ The remove-argument node removes the given argument from the function's
+ signature, and it is a child of the modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <remove-argument />
+ </modify-argument>
+
+rename to
+^^^^^^^^^
+
+ The 'rename to' node is used to rename a argument and use this new name in the generated code.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <rename to='...' />
+ </modify-argument>
+
+
+remove-default-expression
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The remove-default-expression node disables the use of the default expression
+ for the given argument, and it is a child of the modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument...>
+ <remove-default-expression />
+ </modify-argument>
+
+replace-default-expression
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+ The replace-default-expression node replaces the specified argument with the
+ expression specified by the ``with`` attribute, and it is a child of the
+ modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <replace-default-expression with="..." />
+ </modify-argument>
+
+
+replace-type
+^^^^^^^^^^^^
+
+ The replace-type node replaces the type of the given argument to the one
+ specified by the ``modified-type`` attribute, and it is a child of the
+ modify-argument node.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <replace-type modified-type="..." />
+ </modify-argument>
+
+ If the new type is a class, the ``modified-type`` attribute must be set to
+ the fully qualified name (including name of the package as well as the class
+ name).
+
+define-ownership
+^^^^^^^^^^^^^^^^
+
+ The define-ownership tag indicates that the function changes the ownership
+ rules of the argument object. The ``class`` attribute specifies the class of
+ function where to inject the ownership altering code. The ``owner`` attribute
+ specifies the new ownership of the object. It accepts the following values:
+
+ * target: the target language will assume full ownership of the object.
+ The native resources will be deleted when the target language
+ object is finalized.
+ * c++: The native code assumes full ownership of the object. The target
+ language object will not be garbage collected.
+ * default: The object will get default ownership, depending on how it
+ was created.
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <define-ownership class="target | native"
+ owner="target | c++ | default" />
+ </modify-argument>
+
+
+reference-count
+^^^^^^^^^^^^^^^
+
+ The reference-count tag dictates how an argument should be handled by the
+ target language reference counting system (if there is any), it also indicates
+ the kind of relationship the class owning the function being modified has with
+ the argument. For instance, in a model/view relation a view receiving a model
+ as argument for a **setModel** method should increment the model's reference
+ counting, since the model should be kept alive as much as the view lives.
+ Remember that out hypothetical view could not become parent of the model,
+ since the said model could be used by other views as well.
+ The ``action`` attribute specifies what should be done to the argument
+ reference counting when the modified method is called. It accepts the
+ following values:
+
+ * add: increments the argument reference counter.
+ * add-all: increments the reference counter for each item in a collection.
+ * remove: decrements the argument reference counter.
+ * set: will assign the argument to the variable containing the reference.
+ * ignore: does nothing with the argument reference counter
+ (sounds worthless, but could be used in situations
+ where the reference counter increase is mandatory
+ by default).
+
+ .. code-block:: xml
+
+ <modify-argument>
+ <reference-count action="add|add-all|remove|set|ignore" variable-name="..." />
+ </modify-argument>
+
+
+ The variable-name attribute specifies the name used for the variable that
+ holds the reference(s).
+
+
+replace-value
+^^^^^^^^^^^^^
+
+ The ``replace-value`` attribute lets you replace the return statement of a
+ function with a fixed string. This attribute can only be used for the
+ argument at ``index`` 0, which is always the function's return value.
+
+ .. code-block:: xml
+
+ <modify-argument index="0" replace-value="this"/>
+
+
+parent
+^^^^^^
+
+ The parent node lets you define the argument parent which will
+ take ownership of argument and will destroy the C++ child object when the
+ parent is destroyed.
+
+ .. code-block:: xml
+
+ <modify-argument index="1">
+ <parent index="this" action="add | remove" />
+ </modify-argument>
+
+ In the ``index`` argument you must specify the parent argument. The action
+ *add* creates a parent link between objects, while *remove* will undo the
+ parentage relationship.
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_conversionrule.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_conversionrule.rst
new file mode 100644
index 000000000..c62d5bbf6
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_conversionrule.rst
@@ -0,0 +1,113 @@
+.. _conversion-rule-tag:
+
+Conversion Rule Tag
+-------------------
+
+.. _conversion-rule:
+
+conversion-rule
+^^^^^^^^^^^^^^^
+
+ The **conversion-rule** tag specifies how a **primitive-type**, a **container-type**,
+ or a **value-type** may be converted to and from the native C++ language types to the
+ target language types.
+
+ .. code-block:: xml
+
+ <value-type>
+ <conversion-rule>
+ <native-to-target>
+ // Code to convert a native value to a target language object.
+ </native-to-target>
+ <target-to-native>
+ <add-conversion type='TARGETTYPEA' check='TARGETTYPEA_CHECK(%in)'>
+ // Code to convert target language type object of type TARGETTYPEA
+ // to the C++ native type represented by the value/primitive/container-type.
+ </add-conversion>
+ <add-conversion type='TARGETTYPEB' check='TARGETTYPEB_CHECK(%in)'>
+ // Code to convert target language type object of type TARGETTYPEB
+ // to the C++ native type represented by the value/primitive/container-type.
+ </add-conversion>
+ </target-to-native>
+ </conversion-rule>
+ </value-type>
+
+ The example above show the structure of a complete conversion rule. Each of the
+ child tags comprising the conversion rule are described in their own sections
+ below.
+
+
+.. _native-to-target:
+
+native-to-target
+^^^^^^^^^^^^^^^^
+
+ The **native-to-target** tag tells how to convert a native C++ value to its
+ target language equivalent. The text inside the tag is a C++ code the takes
+ an input value an does what's needed to convert it to the output value.
+ ``insert-template`` tags may be used to insert commonly repeating code.
+
+ .. code-block:: xml
+
+ <conversion-rule>
+ <native-to-target>
+ // Code to convert a native value to a target language object.
+ </native-to-target>
+ </conversion-rule>
+
+ Use the replace node to modify the template code.
+ Notice that the generator must provide type system variables for the input
+ and output values and types, namely **%in**, **%out**, **%INTYPE** and
+ **%OUTTYPE**. In the case of container types, **%INTYPE** refers to the
+ full container type (e.g. **"list<int>"**) and **%INTYPE_0**, **%INTYPE_1**,
+ **%INTYPE_#**, should be replaced by the types used in the container template
+ (e.g. **%INTYPE_0** correspondes to **"int"** for **"list<int>"**).
+
+
+.. _target-to-native:
+
+target-to-native
+^^^^^^^^^^^^^^^^
+
+ The **target-to-native** tag encloses at least one, but usually many, conversions
+ from target language values to C++ native values. The *optional* attribute
+ ``replace`` tells if the target language to C++ conversions will be added to, or if
+ they will replace the implicit conversions collected by *ApiExtractor*. The default
+ value for it is *yes*.
+
+
+ .. code-block:: xml
+
+ <conversion-rule>
+ <target-to-native replace='yes|no'>\
+ // List of target to native conversions meant to replace or expand
+ // the already existing implicit conversions.
+ </target-to-native>
+ </conversion-rule>
+
+
+.. _add-conversion:
+
+add-conversion
+^^^^^^^^^^^^^^
+
+ Each **add-conversion** tag adds a rule for conversion of a target language type,
+ indicated by the ``type`` attribute, to the C++ native type represented by the
+ **primitive-type**, a **container-type**, or **value-type**, to which the parent
+ **conversion-rule** belongs.
+
+ .. code-block:: xml
+
+ <target-to-native>
+ <add-conversion type='TARGETTYPE' check='TARGETTYPECHECK(%in)'>
+ // Code to convert target language type object of type TARGETTYPE_A
+ // to the C++ native type represented by the value/primitive/container-type.
+ </add-conversion>
+ <target-to-native>
+
+ The ``check`` attribute tells how a target value should be checked to see if it belongs to
+ the type expected. This attribute is *optional*, for it can be derived from the ``type``
+ attribute, but it isn't unusual that some special check is needed. The variables
+ **%in**, **%out**, **%INTYPE**, **%INTYPE_#**, and **%OUTTYPE**, must be provided by
+ the generator as in the ``native-to-target`` tag.
+
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_documentation.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_documentation.rst
new file mode 100644
index 000000000..43f72a1ba
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_documentation.rst
@@ -0,0 +1,43 @@
+Manipulating Documentation
+--------------------------
+
+inject-documentation
+^^^^^^^^^^^^^^^^^^^^
+
+ The inject-documentation node inserts the documentation into the generated
+ documentation. This node is a child of the object-type, value-type and
+ modify-function nodes.
+
+ .. code-block:: xml
+
+ <value-type>
+ <inject-documentation mode="append | prepend | replace" format="native | target" >
+ // the documentation
+ </inject-code>
+ </value-type>
+
+ The **mode** attribute default value is *replace*.
+
+ The **format** attribute specifies when the documentation injection will
+ occur and it accepts the following values:
+
+ * native: Before XML<->Backend transformation occur, so the injected code *must* be a valid XML.
+ * target: After XML<->Backend transformation occur, so the injected code *must* be a valid backend format.
+
+ At the moment the only supported backend is Sphinx.
+
+modify-documentation
+^^^^^^^^^^^^^^^^^^^^
+
+ The modify-documentation node allows you to change the auto-generated
+ documentation. API Extractor transforms XML's from qdoc3 (the Qt documentation
+ tool) into .rst files to be processed later using Sphinx. So you can modify
+ the XML before the transformation occur.
+
+ .. code-block:: xml
+
+ <modify-documentation xpath="...">
+ <!-- new documentation -->
+ </modify-documentation>
+
+ The **xpath** attribute is the XPath to the node that you want to modify.
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst
new file mode 100644
index 000000000..2838c95e1
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_manipulating_objects.rst
@@ -0,0 +1,132 @@
+.. _manipulating-object-and-value-types:
+
+Manipulating Object and Value Types
+-----------------------------------
+
+.. _inject-code:
+
+inject-code
+^^^^^^^^^^^
+ The inject-code node inserts the given code into the generated code for the
+ given type or function, and it is a child of the :ref:`object-type`, :ref:`value-type`,
+ :ref:`modify-function` and :ref:`add-function` nodes.
+
+ .. code-block:: xml
+
+ <value-type>
+ <inject-code class="native | target | target-declaration"
+ position="beginning | end" since="...">
+ // the code
+ </inject-code>
+ </value-type>
+
+ The ``class`` attribute specifies which module of the generated code that
+ will be affected by the code injection. The ``class`` attribute accepts the
+ following values:
+
+ * native: The c++ code
+ * target: The binding code
+ * target-declaration: The code will be injected into the generated header
+ file containing the c++ wrapper class definition.
+
+ If the ``position`` attribute is set to *beginning* (the default), the code
+ is inserted at the beginning of the function. If it is set to *end*, the code
+ is inserted at the end of the function.
+
+ The ``since`` attribute specify the API version where this code was injected.
+
+modify-field
+^^^^^^^^^^^^
+
+ The modify-field node allows you to alter the access privileges for a given
+ C++ field when mapping it onto the target language, and it is a child of an
+ :ref:`object-type` or a :ref:`value-type` node.
+
+ .. code-block:: xml
+
+ <object-type>
+ <modify-field name="..."
+ write="true | false"
+ read="true | false" />
+ </object-type>
+
+ The ``name`` attribute is the name of the field, the *optional* ``write``
+ and ``read`` attributes specify the field's access privileges in the target
+ language API (both are set to true by default).
+ The ``remove`` attribute is an *optional* attribute, which can mark the field
+ to be discarded on generation; it has the same purpose of the deprecated tag
+ :ref:`remove`.
+
+.. _modify-function:
+
+modify-function
+^^^^^^^^^^^^^^^
+
+ The modify-function node allows you to modify a given C++ function when mapping
+ it onto the target language, and it is a child of an :ref:`object-type` or a :ref:`value-type`
+ node. Use the :ref:`modify-argument` node to specify which argument the modification
+ affects.
+
+ .. code-block:: xml
+
+ <object-type>
+ <modify-function signature="..."
+ since="..."
+ remove="all | c++"
+ access="public | private | protected"
+ rename="..." />
+ </object-type>
+
+ The ``signature`` attribute is a normalized C++ signature, excluding return
+ values but including potential const declarations.
+
+ The ``since`` attribute specify the API version when this function was modified.
+
+ The ``remove``, ``access`` and ``rename`` attributes are *optional* attributes
+ for added convenience; they serve the same purpose as the deprecated tags :ref:`remove`, :ref:`access` and :ref:`rename`.
+
+.. _add-function:
+
+add-function
+^^^^^^^^^^^^
+
+ The add-function node allows you to add a given function onto the target language,
+ and it is a child of an :ref:`object-type` or :ref:`value-type` nodes if the
+ function is suposed to be a method, or :ref:`namespace` and :ref:`typesystem` if
+ the function is suposed to be a function inside a namespace or a global function.
+
+ Typically when adding a function some code must be injected to provide the function
+ logic. This can be done using the :ref:`inject-code` node.
+
+ .. code-block:: xml
+
+ <object-type>
+ <add-function signature="..." return-type="..." access="public | protected" static="yes | no" since="..."/>
+ </object-type>
+
+ The ``return-type`` attribute defaults to *void*, the ``access`` to *public* and the ``static`` one to *no*.
+
+ The ``since`` attribute specify the API version when this function was added.
+
+.. _conversion-rule-on-types:
+
+conversion-rule
+^^^^^^^^^^^^^^^
+
+ The conversion-rule node allows you to write customized code to convert the given argument between the target
+ language and C++, and is a child of the :ref:`value-type`, :ref:`object-type`, :ref:`primitive-type` and
+ :ref:`container-type` nodes.
+
+ The code pointed by the file attribute is very tied to the generator using APIExtractor, so it don't follow any
+ rules, but the generator rules..
+
+ .. code-block:: xml
+
+ <value-type name="Foo">
+ <convertion-rule file="my_converter_implementation.h" since="..."/>
+ </value-type>
+
+ The ``since`` attribute specify the API version when this conversion rule became valid.
+
+ .. note:: You can also use the conversion-rule node to specify :ref:`how the conversion of a single function argument should be done in a function <conversion-rule>`.
+
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_modify_function.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_modify_function.rst
new file mode 100644
index 000000000..071cea4f5
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_modify_function.rst
@@ -0,0 +1,78 @@
+.. _modifying-functions:
+
+Modifying Functions
+-------------------
+
+.. _modify-argument:
+
+modify-argument
+^^^^^^^^^^^^^^^
+
+ The modify-argument node specifies which of the given function's arguments the
+ modification affects, and is a child of the modify-function node. Use the
+ remove-argument, replace-default-expression, remove-default-expression,
+ replace-type, reference-count and define-ownership nodes to specify the details
+ of the modification.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <modify-argument index="return | this | 1 ..." >
+ // modifications
+ </modify-argument>
+ </modify-function>
+
+ Set the ``index`` attribute to "1" for the first argument, "2" for the second
+ one and so on. Alternatively, set it to "return" or "this" if you want to
+ modify the function's return value or the object the function is called upon,
+ respectively.
+
+.. _remove:
+
+remove
+^^^^^^
+
+ The remove node removes the given method from the generated target language
+ API, and it is a child of the modify-function node.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <remove class="all" />
+ </modify-function>
+
+ .. warning:: This tag is deprecated, use the ``remove`` attribute from :ref:`modify-function` tag instead.
+
+.. _access:
+
+access
+^^^^^^
+
+ The access node changes the access privileges of the given function in the
+ generated target language API, and it is a child of the modify-function node.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <access modifier="public | protected | private"/>
+ </modify-function>
+
+ .. warning:: This tag is deprecated, use the ``access`` attribute from :ref:`modify-function` tag instead.
+
+.. _rename:
+
+rename
+^^^^^^
+
+ The rename node changes the name of the given function in the generated target
+ language API, and it is a child of the modify-function node.
+
+ .. code-block:: xml
+
+ <modify-function>
+ <rename to="..." />
+ </modify-function>
+
+ The ``to`` attribute is the new name of the function.
+
+ .. warning:: This tag is deprecated, use the ``rename`` attribute from :ref:`modify-function` tag instead.
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_solving_compilation.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_solving_compilation.rst
new file mode 100644
index 000000000..81d14a187
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_solving_compilation.rst
@@ -0,0 +1,70 @@
+Solving compilation problems
+----------------------------
+
+suppress-warning
+^^^^^^^^^^^^^^^^
+
+ The generator will generate several warnings which may be irrelevant to the
+ user. The suppress-warning node suppresses the specified warning, and it is
+ a child of the typesystem node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <suppress-warning text="..." />
+ </typesystem>
+
+ The **text** attribute is the warning text to suppress, and may contain the *
+ wildcard (use "" to escape regular expression matching if the warning contain
+ a regular "*").
+
+extra-includes
+^^^^^^^^^^^^^^
+
+ The extra-includes node contains declarations of additional include files,
+ and it can be a child of the interface-type, namespace-type, value-type and
+ object-type nodes.
+
+ The generator automatically tries to read the global header for each type but
+ sometimes it is required to include extra files in the generated C++ code to
+ make sure that the code compiles. These files must be listed using include
+ nodes witin the extra-include node:
+
+ .. code-block:: xml
+
+ <value-type>
+ <extra-includes>
+ <include file-name="..." location="global | local"/>
+ </extra-includes>
+ </value-type>
+
+ The **file-name** attribute is the file to include, such as "QStringList".
+ The **location** attribute is where the file is located: *global* means that
+ the file is located in $INCLUDEPATH and will be included using #include <...>,
+ *local* means that the file is in a local directory and will be included
+ using #include "...".
+
+
+include
+^^^^^^^
+
+ The include node specifies the name and location of a file that must be
+ included, and it is a child of the interface-type, namespace-type, value-type,
+ object-type or extra-includes nodes
+
+ The generator automatically tries to read the global header for each type. Use
+ the include node to override this behavior, providing an alternative file. The
+ include node can also be used to specify extra include files.
+
+ .. code-block:: xml
+
+ <value-type>
+ <include file-name="..."
+ location="global | local"/>
+ </value-type>
+
+ The **file-name** attribute is the file to include, such as "QStringList".
+ The **location** attribute is where the file is located: *global* means that
+ the file is located in $INCLUDEPATH and will be included using #include <...>,
+ *local* means that the file is in a local directory and will be included
+ using #include "...".
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
new file mode 100644
index 000000000..0d24a6d52
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_specifying_types.rst
@@ -0,0 +1,371 @@
+Specifying Types
+----------------
+
+.. _typesystem:
+
+typesystem
+^^^^^^^^^^
+
+ This is the root node containing all the type system information. It can
+ have a number of attributes, described below.
+
+ .. code-block:: xml
+
+ <typesystem package="..." default-superclass="...">
+ </typesystem>
+
+ The **package** attribute is a string describing the package to be used,
+ e.g. "QtCore".
+ The *optional* **default-superclass** attribute is the canonical C++ base class
+ name of all objects, e.g., "object".
+
+load-typesystem
+^^^^^^^^^^^^^^^
+
+ The load-typesystem node specifies which type systems to load when mapping
+ multiple libraries to another language or basing one library on another, and
+ it is a child of the typesystem node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <load-typesystem name="..." generate="yes | no" />
+ </typesystem>
+
+ The **name** attribute is the filename of the typesystem to load, the
+ **generate** attribute specifies whether code should be generated or not. The
+ later must be specified when basing one library on another, making the generator
+ able to understand inheritance hierarchies, primitive mapping, parameter types
+ in functions, etc.
+
+ Most libraries will be based on both the QtCore and QtGui modules, in which
+ case code generation for these libraries will be disabled.
+
+
+rejection
+^^^^^^^^^
+
+ The rejection node rejects the given class, or the specified function or
+ field, and it is a child of the typesystem node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <rejection class="..."
+ function-name="..."
+ field-name="..." />
+ </typesystem>
+
+ The **class** attribute is the C++ class name of the class to reject. Use the
+ *optional* **function-name** or **field-name** attributes to reject a particular
+ function or field. Note that the **field-name** and **function-name** cannot
+ be specified at the same time. To remove all occurrences of a given field or
+ function, set the class attribute to \*.
+
+.. _primitive-type:
+
+primitive-type
+^^^^^^^^^^^^^^
+
+ The primitive-type node describes how a primitive type is mapped from C++ to
+ the target language, and is a child of the typesystem node. Note that most
+ primitives are already specified in the QtCore typesystem.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <primitive-type name="..."
+ since="..."
+ target-name="..."
+ default-constructor="..."
+ preferred-conversion="yes | no" />
+ </typesystem>
+
+ The **name** attribute is the name of the primitive in C++, the optional,
+ **target-name** attribute is the name of the primitive type in the target
+ language. If the later two attributes are not specified their default value
+ will be the same as the **name** attribute.
+
+ The *optional* **since** value is used to specify the API version of this type.
+
+ If the *optional* **preferred-conversion** attribute is set to *no*, it
+ indicates that this version of the primitive type is not the preferred C++
+ equivalent of the target language type. For example, in Python both "qint64"
+ and "long long" become "long" but we should prefer the "qint64" version. For
+ this reason we mark "long long" with preferred-conversion="no".
+
+ The *optional* **default-constructor** specifies the minimal constructor
+ call to build one value of the primitive-type. This is not needed when the
+ primitive-type may be built with a default constructor (the one without
+ arguments).
+
+ The *optional* **preferred-conversion** attribute tells how to build a default
+ instance of the primitive type. It should be a constructor call capable of
+ creating a instance of the primitive type. Example: a class "Foo" could have
+ a **preferred-conversion** value set to "Foo()". Usually this attribute is
+ used only for classes declared as primitive types and not for primitive C++
+ types, but that depends on the application using *ApiExtractor*.
+
+
+.. _namespace:
+
+namespace-type
+^^^^^^^^^^^^^^
+
+ The namespace-type node maps the given C++ namespace to the target language,
+ and it is a child of the typesystem node. Note that within namespaces, the
+ generator only supports enums (i.e., no functions or classes).
+
+ .. code-block:: xml
+
+ <typesystem>
+ <namespace-type name="..."
+ generate="yes | no"
+ package="..."
+ since="..."
+ revision="..." />
+ </typesystem>
+
+ The **name** attribute is the name of the namespace, e.g., "Qt".
+
+ The *optional* **generate** attribute is used to inform if you need to prepend
+ the given namespace into each generated class. Its default value is **yes**.
+
+ The **package** attribute can be used to override the package of the type system.
+
+ The *optional* **since** value is used to specify the API version of this type.
+
+ The **revision** attribute can be used to specify a revision for each type, easing the
+ production of ABI compatible bindings.
+
+enum-type
+^^^^^^^^^
+
+ The enum-type node maps the given enum from C++ to the target language,
+ and it is a child of the typesystem node. Use the reject-enum-value to
+ reject values.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <enum-type name="..."
+ identified-by-value="..."
+ since="..."
+ flags="yes | no"
+ flags-revision="..."
+ lower-bound="..."
+ upper-bound="..."
+ force-integer="yes | no"
+ extensible="yes | no"
+ revision="..." />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ name of the enum
+ (e.g.,"Qt::FillRule"). If the *optional* **flags** attribute is set to *yes*
+ (the default is *no*), the generator will expect an existing QFlags<T> for the
+ given enum type. The **lower-bound** and **upper-bound** attributes are used
+ to specify runtime bounds checking for the enum value. The value must be a
+ compilable target language statement, such as "QGradient.Spread.PadSpread"
+ (taking again Python as an example). If the **force-integer** attribute is
+ set to *yes* (the default is *no*), the generated target language code will
+ use the target language integers instead of enums. And finally, the
+ **extensible** attribute specifies whether the given enum can be extended
+ with user values (the default is *no*).
+
+ The *optional* **since** value is used to specify the API version of this type.
+
+ The attribute **identified-by-value** helps to specify anonymous enums using the
+ name of one of their values, which is unique for the anonymous enum scope.
+ Notice that the **enum-type** tag can either have **name** or **identified-by-value**
+ but not both.
+
+ The **revision** attribute can be used to specify a revision for each type, easing the
+ production of ABI compatible bindings.
+
+ The **flags-revision** attribute has the same purposes of **revision** attribute but
+ is used for the QFlag related to this enum.
+
+
+reject-enum-value
+^^^^^^^^^^^^^^^^^
+
+ The reject-enum-value node rejects the enum value specified by the **name**
+ attribute, and it is a child of the enum-type node.
+
+ .. code-block:: xml
+
+ <enum-type>
+ <reject-enum-value name="..."/>
+ </enum-type>
+
+ This node is used when a C++ enum implementation has several identical numeric
+ values, some of which are typically obsolete.
+
+.. _value-type:
+
+value-type
+^^^^^^^^^^
+
+ The value-type node indicates that the given C++ type is mapped onto the target
+ language as a value type. This means that it is an object passed by value on C++,
+ i.e. it is stored in the function call stack. It is a child of the :ref:`typesystem` node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <value-type name="..." since="..."
+ copyable="yes | no"
+ hash-function="..."
+ stream="yes | no"
+ default-constructor="..."
+ revision="..." />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ class name, such as
+ "QMatrix" or "QPainterPath::Element". The **copyable** attribute is used to
+ force or not specify if this type is copyable. The *optional* **hash-function**
+ attribute informs the function name of a hash function for the type.
+
+ The *optional* attribute **stream** specifies whether this type will be able to
+ use externally defined operators, like QDataStream << and >>. If equals to **yes**,
+ these operators will be called as normal methods within the current class.
+
+ The *optional* **since** value is used to specify the API version of this type.
+
+ The *optional* **default-constructor** specifies the minimal constructor
+ call to build one instance of the value-type. This is not needed when the
+ value-type may be built with a default constructor (the one without arguments).
+ Usually a code generator may guess a minimal constructor for a value-type based
+ on its constructor signatures, thus **default-constructor** is used only in
+ very odd cases.
+
+ The **revision** attribute can be used to specify a revision for each type, easing the
+ production of ABI compatible bindings.
+
+.. _object-type:
+
+object-type
+^^^^^^^^^^^
+
+ The object-type node indicates that the given C++ type is mapped onto the target
+ language as an object type. This means that it is an object passed by pointer on
+ C++ and it is stored on the heap. It is a child of the :ref:`typesystem` node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <object-type name="..."
+ since="..."
+ copyable="yes | no"
+ hash-function="..."
+ stream="yes | no"
+ revision="..." />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ class name. If there is no
+ C++ base class, the default-superclass attribute can be used to specify a
+ superclass for the given type, in the generated target language API. The
+ **copyable** and **hash-function** attributes are the same as described for
+ :ref:`value-type`.
+
+ The *optional* attribute **stream** specifies whether this type will be able to
+ use externally defined operators, like QDataStream << and >>. If equals to **yes**,
+ these operators will be called as normal methods within the current class.
+
+ The *optional* **since** value is used to specify the API version of this type.
+
+ The **revision** attribute can be used to specify a revision for each type, easing the
+ production of ABI compatible bindings.
+
+interface-type
+^^^^^^^^^^^^^^
+
+ The interface-type node indicates that the given class is replaced by an
+ interface pattern when mapping from C++ to the target language. Using the
+ interface-type node implicitly makes the given type an :ref:`object-type`.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <interface-type name="..."
+ since="..."
+ package ="..."
+ default-superclass ="..."
+ revision="..." />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ class name. The *optional*
+ **package** attribute can be used to override the package of the type system.
+ If there is no C++ base class, the *optional* **default-superclass** attribute
+ can be used to specify a superclass in the generated target language API, for
+ the given class.
+
+ The *optional* **since** value is used to specify the API version of this interface.
+
+ The **revision** attribute can be used to specify a revision for each type, easing the
+ production of ABI compatible bindings.
+
+.. _container-type:
+
+container-type
+^^^^^^^^^^^^^^
+
+ The container-type node indicates that the given class is a container and
+ must be handled using one of the conversion helpers provided by attribute **type**.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <container-type name="..."
+ since="..."
+ type ="..." />
+ </typesystem>
+
+ The **name** attribute is the fully qualified C++ class name. The **type**
+ attribute is used to indicate what conversion rule will be applied to the
+ container. It can be: *list*, *string-list*, *linked-list*, *vector*, *stack*,
+ *queue*, *set*, *map*, *multi-map*, *hash*, *multi-hash* or *pair*.
+
+ The *optional* **since** value is used to specify the API version of this container.
+
+
+.. _custom-type:
+
+custom-type
+^^^^^^^^^^^
+
+ The custom-type node simply makes the parser aware of the existence of a target
+ language type, thus avoiding errors when trying to find a type used in function
+ signatures and other places. The proper handling of the custom type is meant to
+ be done by a generator using the APIExractor.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <custom-type name="..." />
+ </typesystem>
+
+ The **name** attribute is the name of the custom type, e.g., "PyObject".
+
+
+.. _function:
+
+function
+^^^^^^^^
+
+ The function node indicates that the given C++ global function is mapped onto
+ the target language.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <function signature="..." rename="..." since="..."/>
+ </typesystem>
+
+ This tag has some limitations, it doesn't support function modifications, besides you
+ can't add a function overload using :ref:`add-function` tag to an existent function.
+ These limitation will be addressed in future versions of ApiExtractor.
+
+ The function tag has two *optional* attributes: **since**, whose value is used to specify
+ the API version of this function, and **rename**, to modify the function name.
+
diff --git a/sources/shiboken2/ApiExtractor/doc/typesystem_templates.rst b/sources/shiboken2/ApiExtractor/doc/typesystem_templates.rst
new file mode 100644
index 000000000..31b155c5a
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doc/typesystem_templates.rst
@@ -0,0 +1,55 @@
+.. _using-code-templates:
+
+Using Code Templates
+--------------------
+
+template
+^^^^^^^^
+
+ The template node registers a template that can be used to avoid duplicate
+ code when extending the generated code, and it is a child of the typesystem
+ node.
+
+ .. code-block:: xml
+
+ <typesystem>
+ <template name="my_template">
+ // the code
+ </template>
+ </typesystem>
+
+ Use the insert-template node to insert the template code (identified by the
+ template's ``name`` attribute) into the generated code base.
+
+
+insert-template
+^^^^^^^^^^^^^^^
+
+ The insert-template node includes the code template identified by the name
+ attribute, and it can be a child of the inject-code, conversion-rule, template,
+ custom-constructor and custom-destructor nodes.
+
+ .. code-block:: xml
+
+ <inject-code class="target" position="beginning">
+ <insert-template name="my_template" />
+ </inject-code>
+
+ Use the replace node to modify the template code.
+
+
+replace
+^^^^^^^
+
+ The replace node allows you to modify template code before inserting it into
+ the generated code, and it can be a child of the insert-template node.
+
+ .. code-block:: xml
+
+ <insert-template name="my_template">
+ <replace from="..." to="..." />
+ </insert-template>
+
+ This node will replace the attribute ``from`` with the value pointed by
+ ``to``.
+
diff --git a/sources/shiboken2/ApiExtractor/docparser.cpp b/sources/shiboken2/ApiExtractor/docparser.cpp
new file mode 100644
index 000000000..bae438f18
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/docparser.cpp
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "docparser.h"
+#include "abstractmetalang.h"
+#include "typesystem.h"
+#include <QtCore/QDebug>
+#include <QtXmlPatterns/QXmlQuery>
+#include <QBuffer>
+
+#include <cstdlib>
+#include <libxslt/xsltutils.h>
+#include <libxslt/transform.h>
+
+DocParser::DocParser()
+{
+ xmlSubstituteEntitiesDefault(1);
+}
+
+DocParser::~DocParser()
+{
+}
+
+QString DocParser::getDocumentation(QXmlQuery& xquery, const QString& query,
+ const DocModificationList& mods) const
+{
+ QString doc = execXQuery(xquery, query);
+ return applyDocModifications(mods, doc);
+}
+
+QString DocParser::execXQuery(QXmlQuery& xquery, const QString& query) const
+{
+ QString escapedQuery(query);
+ // XQuery can't have invalid XML characters
+ escapedQuery.replace(QLatin1Char('&'), QLatin1String("&amp;"));
+ escapedQuery.replace(QLatin1Char('<'), QLatin1String("&lt;"));
+ xquery.setQuery(escapedQuery);
+ if (!xquery.isValid()) {
+ qWarning() << "Bad XQuery: " << escapedQuery;
+ return QString();
+ }
+
+ QString result;
+ xquery.evaluateTo(&result);
+ return result;
+}
+
+namespace
+{
+
+struct XslResources
+{
+ xmlDocPtr xmlDoc;
+ xsltStylesheetPtr xslt;
+ xmlDocPtr xslResult;
+
+ XslResources() : xmlDoc(0), xslt(0), xslResult(0) {}
+
+ ~XslResources()
+ {
+ if (xslt)
+ xsltFreeStylesheet(xslt);
+
+ if (xslResult)
+ xmlFreeDoc(xslResult);
+
+ if (xmlDoc)
+ xmlFreeDoc(xmlDoc);
+
+ xsltCleanupGlobals();
+ xmlCleanupParser();
+ }
+};
+
+} // namespace
+
+QString DocParser::applyDocModifications(const DocModificationList& mods, const QString& xml) const
+{
+ if (mods.isEmpty())
+ return xml;
+
+ bool hasXPathBasedModification = false;
+ for (const DocModification &mod : mods) {
+ if (mod.mode() == TypeSystem::DocModificationXPathReplace) {
+ hasXPathBasedModification = true;
+ break;
+ }
+ }
+
+ if (!hasXPathBasedModification)
+ return xml;
+
+ QString xsl = QLatin1String("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ "<xsl:transform version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">\n"
+ "<xsl:template match=\"/\">\n"
+ " <xsl:apply-templates />\n"
+ "</xsl:template>\n"
+ "<xsl:template match=\"*\">\n"
+ "<xsl:copy>\n"
+ " <xsl:copy-of select=\"@*\"/>\n"
+ " <xsl:apply-templates/>\n"
+ "</xsl:copy>\n"
+ "</xsl:template>\n"
+ );
+ for (const DocModification &mod : mods) {
+ if (mod.mode() == TypeSystem::DocModificationXPathReplace) {
+ QString xpath = mod.xpath();
+ xpath.replace(QLatin1Char('"'), QLatin1String("&quot;"));
+ xsl += QLatin1String("<xsl:template match=\"")
+ + xpath + QLatin1String("\">")
+ + mod.code() + QLatin1String("</xsl:template>\n");
+ }
+ }
+ xsl += QLatin1String("</xsl:transform>");
+
+ XslResources res;
+ // Read XML data
+ QByteArray xmlData = xml.toUtf8();
+ res.xmlDoc = xmlParseMemory(xmlData.constData(), xmlData.size());
+ if (!res.xmlDoc)
+ return xml;
+
+ // Read XSL data as a XML file
+ QByteArray xslData = xsl.toUtf8();
+ // xsltFreeStylesheet will delete this pointer
+ xmlDocPtr xslDoc = xmlParseMemory(xslData.constData(), xslData.size());
+ if (!xslDoc)
+ return xml;
+
+ // Parse XSL data
+ res.xslt = xsltParseStylesheetDoc(xslDoc);
+ if (!res.xslt)
+ return xml;
+
+ // Apply XSL
+ res.xslResult = xsltApplyStylesheet(res.xslt, res.xmlDoc, 0);
+ xmlChar* buffer = 0;
+ int bufferSize;
+ QString result;
+ if (!xsltSaveResultToString(&buffer, &bufferSize, res.xslResult, res.xslt)) {
+ result = QString::fromUtf8(reinterpret_cast<char*>(buffer), bufferSize);
+ std::free(buffer);
+ } else {
+ result = xml;
+ }
+
+ Q_ASSERT(result != xml);
+ return result;
+}
+
diff --git a/sources/shiboken2/ApiExtractor/docparser.h b/sources/shiboken2/ApiExtractor/docparser.h
new file mode 100644
index 000000000..5573f6851
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/docparser.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef DOCPARSER_H
+#define DOCPARSER_H
+
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QString>
+
+QT_BEGIN_NAMESPACE
+class QDomDocument;
+class QDomNode;
+class QXmlQuery;
+QT_END_NAMESPACE
+
+class AbstractMetaClass;
+class DocModification;
+class Documentation;
+
+class DocParser
+{
+public:
+ DocParser();
+ virtual ~DocParser();
+ virtual void fillDocumentation(AbstractMetaClass* metaClass) = 0;
+
+ /**
+ * Process and retrieves documentation concerning the entire
+ * module or library.
+ * \return object containing module/library documentation information
+ */
+ virtual Documentation retrieveModuleDocumentation() = 0;
+
+ void setDocumentationDataDirectory(const QString& dir)
+ {
+ m_docDataDir = dir;
+ }
+
+ /**
+ * Informs the location of the XML data generated by the tool
+ * (e.g.: DoxyGen, qdoc) used to extract the library's documentation
+ * comment.
+ * \return the path for the directory containing the XML data created
+ * from the library's documentation beign parsed.
+ */
+ QString documentationDataDirectory() const
+ {
+ return m_docDataDir;
+ }
+
+ void setLibrarySourceDirectory(const QString& dir)
+ {
+ m_libSourceDir = dir;
+ }
+ /**
+ * Informs the location of the library being parsed. The library
+ * source code is parsed for the documentation comments.
+ * \return the path for the directory containing the source code of
+ * the library beign parsed.
+ */
+ QString librarySourceDirectory() const
+ {
+ return m_libSourceDir;
+ }
+
+ void setPackageName(const QString& packageName)
+ {
+ m_packageName = packageName;
+ }
+ /**
+ * Retrieves the name of the package (or module or library) being parsed.
+ * \return the name of the package (module/library) being parsed
+ */
+ QString packageName() const
+ {
+ return m_packageName;
+ }
+
+ /**
+ * Process and retrieves documentation concerning the entire
+ * module or library.
+ * \param name module name
+ * \return object containing module/library documentation information
+ * \todo Merge with retrieveModuleDocumentation() on next ABI change.
+ */
+ virtual Documentation retrieveModuleDocumentation(const QString& name) = 0;
+
+protected:
+ QString getDocumentation(QXmlQuery& xquery, const QString& query,
+ const DocModificationList& mods) const;
+
+private:
+ QString m_packageName;
+ QString m_docDataDir;
+ QString m_libSourceDir;
+
+ QString execXQuery(QXmlQuery& xquery, const QString& query) const;
+ QString applyDocModifications(const DocModificationList& mods, const QString& xml) const;
+};
+
+#endif // DOCPARSER_H
+
diff --git a/sources/shiboken2/ApiExtractor/doxygenparser.cpp b/sources/shiboken2/ApiExtractor/doxygenparser.cpp
new file mode 100644
index 000000000..6b90fe6fc
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doxygenparser.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "doxygenparser.h"
+#include "abstractmetalang.h"
+#include "reporthandler.h"
+#include "typesystem.h"
+
+#include <QtXmlPatterns/QXmlQuery>
+#include <QtCore/QFile>
+#include <QtCore/QDir>
+
+namespace
+{
+
+QString getSectionKindAttr(const AbstractMetaFunction* func)
+{
+ if (func->isSignal()) {
+ return QLatin1String("signal");
+ } else {
+ QString kind = func->isPublic() ? QLatin1String("public") : QLatin1String("protected");
+ if (func->isStatic())
+ kind += QLatin1String("-static");
+ else if (func->isSlot())
+ kind += QLatin1String("-slot");
+ return kind;
+ }
+}
+
+}
+
+Documentation DoxygenParser::retrieveModuleDocumentation()
+{
+ return retrieveModuleDocumentation(packageName());
+}
+
+void DoxygenParser::fillDocumentation(AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return;
+
+ QString doxyFileSuffix;
+ if (metaClass->enclosingClass()) {
+ doxyFileSuffix += metaClass->enclosingClass()->name();
+ doxyFileSuffix += QLatin1String("_1_1"); // FIXME: Check why _1_1!!
+ }
+ doxyFileSuffix += metaClass->name();
+ doxyFileSuffix += QLatin1String(".xml");
+
+ const char* prefixes[] = { "class", "struct", "namespace" };
+ const int numPrefixes = sizeof(prefixes) / sizeof(const char*);
+ bool isProperty = false;
+
+ QString doxyFilePath;
+ for (int i = 0; i < numPrefixes; ++i) {
+ doxyFilePath = documentationDataDirectory() + QLatin1Char('/')
+ + QLatin1String(prefixes[i]) + doxyFileSuffix;
+ if (QFile::exists(doxyFilePath))
+ break;
+ doxyFilePath.clear();
+ }
+
+ if (doxyFilePath.isEmpty()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't find doxygen file for class " << metaClass->name() << ", tried: "
+ << QDir::toNativeSeparators(documentationDataDirectory())
+ << "/{struct|class|namespace}"<< doxyFileSuffix;
+ return;
+ }
+ QXmlQuery xquery;
+ xquery.setFocus(QUrl(doxyFilePath));
+
+ // Get class documentation
+ QString classDoc = getDocumentation(xquery, QLatin1String("/doxygen/compounddef/detaileddescription"),
+ metaClass->typeEntry()->docModifications());
+ if (classDoc.isEmpty()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't find documentation for class \"" << metaClass->name() << "\".";
+ }
+ metaClass->setDocumentation(classDoc);
+
+ //Functions Documentation
+ const AbstractMetaFunctionList &funcs = metaClass->functionsInTargetLang();
+ for (AbstractMetaFunction *func : funcs) {
+ if (!func || func->isPrivate())
+ continue;
+
+ QString query = QLatin1String("/doxygen/compounddef/sectiondef");
+ // properties
+ if (func->isPropertyReader() || func->isPropertyWriter()
+ || func->isPropertyResetter()) {
+ query += QLatin1String("[@kind=\"property\"]/memberdef/name[text()=\"")
+ + func->propertySpec()->name() + QLatin1String("\"]");
+ isProperty = true;
+ } else { // normal methods
+ QString kind = getSectionKindAttr(func);
+ query += QLatin1String("[@kind=\"") + kind
+ + QLatin1String("-func\"]/memberdef/name[text()=\"")
+ + func->originalName() + QLatin1String("\"]");
+
+ if (func->arguments().isEmpty()) {
+ QString args = func->isConstant() ? QLatin1String("() const ") : QLatin1String("()");
+ query += QLatin1String("/../argsstring[text()=\"") + args + QLatin1String("\"]");
+ } else {
+ int i = 1;
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (AbstractMetaArgument *arg : arguments) {
+ if (!arg->type()->isPrimitive()) {
+ query += QLatin1String("/../param[") + QString::number(i)
+ + QLatin1String("]/type/ref[text()=\"")
+ + arg->type()->name() + QLatin1String("\"]/../..");
+ } else {
+ query += QLatin1String("/../param[") + QString::number(i)
+ + QLatin1String("]/type[text()=\"")
+ + arg->type()->name() + QLatin1String("\"]/..");
+ }
+ ++i;
+ }
+ }
+ }
+ if (!isProperty) {
+ query += QLatin1String("/../detaileddescription");
+ } else {
+ query = QLatin1Char('(') + query;
+ query += QLatin1String("/../detaileddescription)[1]");
+ }
+ QString doc = getDocumentation(xquery, query, DocModificationList());
+ func->setDocumentation(doc);
+ isProperty = false;
+ }
+
+ //Fields
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (AbstractMetaField *field : fields) {
+ if (field->isPrivate())
+ return;
+
+ QString query = QLatin1String("/doxygen/compounddef/sectiondef/memberdef/name[text()=\"")
+ + field->name() + QLatin1String("\"]/../detaileddescription");
+ QString doc = getDocumentation(xquery, query, DocModificationList());
+ field->setDocumentation(doc);
+ }
+
+ //Enums
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (AbstractMetaEnum *meta_enum : enums) {
+ QString query = QLatin1String("/doxygen/compounddef/sectiondef/memberdef[@kind=\"enum\"]/name[text()=\"")
+ + meta_enum->name() + QLatin1String("\"]/..");
+ QString doc = getDocumentation(xquery, query, DocModificationList());
+ meta_enum->setDocumentation(doc);
+ }
+
+}
+
+Documentation DoxygenParser::retrieveModuleDocumentation(const QString& name){
+
+ QString sourceFile = documentationDataDirectory() + QLatin1String("/indexpage.xml");
+
+ if (!QFile::exists(sourceFile)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't find doxygen XML file for module " << name << ", tried: "
+ << QDir::toNativeSeparators(sourceFile);
+ return Documentation();
+ }
+
+ QXmlQuery xquery;
+ xquery.setFocus(QUrl(sourceFile));
+
+ // Module documentation
+ QString query = QLatin1String("/doxygen/compounddef/detaileddescription");
+ return Documentation(getDocumentation(xquery, query, DocModificationList()));
+}
+
diff --git a/sources/shiboken2/ApiExtractor/doxygenparser.h b/sources/shiboken2/ApiExtractor/doxygenparser.h
new file mode 100644
index 000000000..3f9ca5142
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/doxygenparser.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DOXYGENPARSER_H
+#define DOXYGENPARSER_H
+
+#include "docparser.h"
+
+class DoxygenParser : public DocParser
+{
+public:
+ DoxygenParser() {}
+ void fillDocumentation(AbstractMetaClass *metaClass) override;
+ Documentation retrieveModuleDocumentation() override;
+ Documentation retrieveModuleDocumentation(const QString& name) override;
+};
+
+#endif // DOXYGENPARSER_H
diff --git a/sources/shiboken2/ApiExtractor/fileout.cpp b/sources/shiboken2/ApiExtractor/fileout.cpp
new file mode 100644
index 000000000..c97347fe1
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/fileout.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "fileout.h"
+#include "reporthandler.h"
+
+#include <QtCore/QTextCodec>
+#include <QtCore/QFileInfo>
+#include <QtCore/QDir>
+
+#include <cstdio>
+
+bool FileOut::dummy = false;
+bool FileOut::diff = false;
+
+#ifdef Q_OS_LINUX
+const char* colorDelete = "\033[31m";
+const char* colorAdd = "\033[32m";
+const char* colorInfo = "\033[36m";
+const char* colorReset = "\033[0m";
+#else
+const char* colorDelete = "";
+const char* colorAdd = "";
+const char* colorInfo = "";
+const char* colorReset = "";
+#endif
+
+FileOut::FileOut(QString n):
+ name(n),
+ stream(&tmp),
+ isDone(false)
+{}
+
+static int* lcsLength(QList<QByteArray> a, QList<QByteArray> b)
+{
+ const int height = a.size() + 1;
+ const int width = b.size() + 1;
+
+ int *res = new int[width * height];
+
+ for (int row = 0; row < height; row++)
+ res[width * row] = 0;
+
+ for (int col = 0; col < width; col++)
+ res[col] = 0;
+
+ for (int row = 1; row < height; row++) {
+ for (int col = 1; col < width; col++) {
+ if (a[row-1] == b[col-1])
+ res[width * row + col] = res[width * (row-1) + col-1] + 1;
+ else
+ res[width * row + col] = qMax(res[width * row + col-1],
+ res[width * (row-1) + col]);
+ }
+ }
+ return res;
+}
+
+enum Type {
+ Add,
+ Delete,
+ Unchanged
+};
+
+struct Unit
+{
+ Unit(Type type, int pos) :
+ type(type),
+ start(pos),
+ end(pos) {}
+
+ Type type;
+ int start;
+ int end;
+
+ void print(QList<QByteArray> a, QList<QByteArray> b)
+ {
+ if (type == Unchanged) {
+ if ((end - start) > 9) {
+ for (int i = start; i <= start + 2; i++)
+ std::printf(" %s\n", a[i].data());
+ std::printf("%s=\n= %d more lines\n=%s\n", colorInfo, end - start - 6, colorReset);
+ for (int i = end - 2; i <= end; i++)
+ std::printf(" %s\n", a[i].data());
+ } else {
+ for (int i = start; i <= end; i++)
+ std::printf(" %s\n", a[i].data());
+ }
+ } else if (type == Add) {
+ std::printf("%s", colorAdd);
+ for (int i = start; i <= end; i++)
+ std::printf("+ %s\n", b[i].data());
+ std::printf("%s", colorReset);
+ } else if (type == Delete) {
+ std::printf("%s", colorDelete);
+ for (int i = start; i <= end; i++)
+ std::printf("- %s\n", a[i].data());
+ std::printf("%s", colorReset);
+ }
+ }
+};
+
+static QList<Unit*> *unitAppend(QList<Unit*> *res, Type type, int pos)
+{
+ if (!res) {
+ res = new QList<Unit*>;
+ res->append(new Unit(type, pos));
+ return res;
+ }
+
+ Unit *last = res->last();
+ if (last->type == type)
+ last->end = pos;
+ else
+ res->append(new Unit(type, pos));
+
+ return res;
+}
+
+static QList<Unit*> *diffHelper(int *lcs, QList<QByteArray> a, QList<QByteArray> b, int row, int col)
+{
+ if (row > 0 && col > 0 && (a[row-1] == b[col-1])) {
+ return unitAppend(diffHelper(lcs, a, b, row - 1, col - 1), Unchanged, row - 1);
+ } else {
+ int width = b.size() + 1;
+ if ((col > 0)
+ && (row == 0 || lcs[width * row + col-1] >= lcs[width *(row-1) + col])) {
+ return unitAppend(diffHelper(lcs, a, b, row, col - 1), Add, col - 1);
+ } else if ((row > 0)
+ && (col == 0 || lcs[width * row + col-1] < lcs[width *(row-1) + col])) {
+ return unitAppend(diffHelper(lcs, a, b, row - 1, col), Delete, row - 1);
+ }
+ }
+ delete lcs;
+ return 0;
+}
+
+static void diff(QList<QByteArray> a, QList<QByteArray> b)
+{
+ QList<Unit*> *res = diffHelper(lcsLength(a, b), a, b, a.size(), b.size());
+ for (int i = 0; i < res->size(); i++) {
+ Unit *unit = res->at(i);
+ unit->print(a, b);
+ delete(unit);
+ }
+ delete(res);
+}
+
+
+FileOut::State FileOut::done()
+{
+ Q_ASSERT(!isDone);
+ if (name.isEmpty())
+ return Failure;
+
+ isDone = true;
+ bool fileEqual = false;
+ QFile fileRead(name);
+ QFileInfo info(fileRead);
+ stream.flush();
+ QByteArray original;
+ if (info.exists() && (diff || (info.size() == tmp.size()))) {
+ if (!fileRead.open(QIODevice::ReadOnly)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("failed to open file '%1' for reading")
+ .arg(QDir::toNativeSeparators(fileRead.fileName()));
+ return Failure;
+ }
+
+ original = fileRead.readAll();
+ fileRead.close();
+ fileEqual = (original == tmp);
+ }
+
+ if (fileEqual)
+ return Unchanged;
+
+ if (!FileOut::dummy) {
+ QDir dir(info.absolutePath());
+ if (!dir.mkpath(dir.absolutePath())) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("unable to create directory '%1'")
+ .arg(QDir::toNativeSeparators(dir.absolutePath()));
+ return Failure;
+ }
+
+ QFile fileWrite(name);
+ if (!fileWrite.open(QIODevice::WriteOnly)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("failed to open file '%1' for writing")
+ .arg(QDir::toNativeSeparators(fileWrite.fileName()));
+ return Failure;
+ }
+ QTextCodec *codec = QTextCodec::codecForName("UTF-8");
+ stream.setCodec(codec);
+ stream.setDevice(&fileWrite);
+ stream << tmp;
+ }
+ if (diff) {
+ std::printf("%sFile: %s%s\n", colorInfo, qPrintable(name), colorReset);
+ ::diff(original.split('\n'), tmp.split('\n'));
+ std::printf("\n");
+ }
+
+ return Success;
+}
diff --git a/sources/shiboken2/ApiExtractor/fileout.h b/sources/shiboken2/ApiExtractor/fileout.h
new file mode 100644
index 000000000..14ce3a251
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/fileout.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef FILEOUT_H
+#define FILEOUT_H
+
+#include <QtCore/QObject>
+#include <QtCore/QTextStream>
+
+class FileOut : public QObject
+{
+private:
+ QByteArray tmp;
+ QString name;
+
+public:
+ enum State { Failure, Unchanged, Success };
+
+ FileOut(QString name);
+ ~FileOut()
+ {
+ if (!isDone)
+ done();
+ }
+
+ State done();
+
+ QTextStream stream;
+
+ static bool dummy;
+ static bool diff;
+
+private:
+ bool isDone;
+};
+
+#endif // FILEOUT_H
diff --git a/sources/shiboken2/ApiExtractor/graph.cpp b/sources/shiboken2/ApiExtractor/graph.cpp
new file mode 100644
index 000000000..e6ee660dc
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/graph.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "graph.h"
+#include <QVector>
+#include <QDebug>
+#include <QLinkedList>
+#include <QSet>
+#include <iterator>
+#include <algorithm>
+#include <iostream>
+#include <QFile>
+
+struct Graph::GraphPrivate
+{
+ enum Color { WHITE, GRAY, BLACK };
+ typedef QVector<QSet<int> > Edges;
+ typedef QSet<int>::const_iterator EdgeIterator;
+
+ Edges edges;
+
+ GraphPrivate(int numNodes) : edges(numNodes)
+ {
+ }
+
+ void dfsVisit(int node, QLinkedList<int>& result, QVector<Color>& colors) const
+ {
+ colors[node] = GRAY;
+ EdgeIterator it = edges[node].begin();
+ for (; it != edges[node].end(); ++it) {
+ if (colors[*it] == WHITE)
+ dfsVisit(*it, result, colors);
+ else if (colors[*it] == GRAY) // This is not a DAG!
+ return;
+ }
+ colors[node] = BLACK;
+ result.push_front(node);
+ }
+};
+
+Graph::Graph(int numNodes) : m_d(new GraphPrivate(numNodes))
+{
+}
+
+Graph::~Graph()
+{
+ delete m_d;
+}
+
+int Graph::nodeCount() const
+{
+ return m_d->edges.size();
+}
+
+QLinkedList<int> Graph::topologicalSort() const
+{
+ int nodeCount = Graph::nodeCount();
+ QLinkedList<int> result;
+ QVector<GraphPrivate::Color> colors(nodeCount, GraphPrivate::WHITE);
+
+ for (int i = 0; i < nodeCount; ++i) {
+ if (colors[i] == GraphPrivate::WHITE)
+ m_d->dfsVisit(i, result, colors);
+ }
+
+ // Not a DAG!
+ if (result.size() != nodeCount)
+ return QLinkedList<int>();
+ return result;
+}
+
+bool Graph::containsEdge(int from, int to)
+{
+ return m_d->edges[from].contains(to);
+}
+
+void Graph::addEdge(int from, int to)
+{
+ Q_ASSERT(to < (int)m_d->edges.size());
+ m_d->edges[from].insert(to);
+}
+
+void Graph::removeEdge(int from, int to)
+{
+ m_d->edges[from].remove(to);
+}
+
+void Graph::dump() const
+{
+ for (int i = 0; i < m_d->edges.size(); ++i) {
+ std::cout << i << " -> ";
+ std::copy(m_d->edges[i].begin(), m_d->edges[i].end(), std::ostream_iterator<int>(std::cout, " "));
+ std::cout << std::endl;
+ }
+}
+
+void Graph::dumpDot(const QHash< int, QString >& nodeNames, const QString& fileName) const
+{
+ QFile output(fileName);
+ if (!output.open(QIODevice::WriteOnly))
+ return;
+ QTextStream s(&output);
+ s << "digraph D {\n";
+ for (int i = 0; i < m_d->edges.size(); ++i) {
+ GraphPrivate::EdgeIterator it = m_d->edges[i].begin();
+ for (;it != m_d->edges[i].end(); ++it)
+ s << '"' << nodeNames[i] << "\" -> \"" << nodeNames[*it] << "\"\n";
+ }
+ s << "}\n";
+}
diff --git a/sources/shiboken2/ApiExtractor/graph.h b/sources/shiboken2/ApiExtractor/graph.h
new file mode 100644
index 000000000..78b931320
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/graph.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GRAPH_H
+#define GRAPH_H
+
+#include <QLinkedList>
+#include <QHash>
+#include <QString>
+
+/// A graph that can have their nodes topologically sorted.
+class Graph
+{
+public:
+ /// Create a new graph with \p numNodes nodes.
+ Graph(int numNodes);
+ ~Graph();
+
+ /// Returns the numbed of nodes in this graph.
+ int nodeCount() const;
+ /// Returns true if the graph contains the edge from -> to
+ bool containsEdge(int from, int to);
+ /// Adds an edge to this graph.
+ void addEdge(int from, int to);
+ /// Removes an edge out of this graph.
+ void removeEdge(int from, int to);
+ /// Print this graph to stdout.
+ void dump() const;
+ /**
+ * Dumps a dot graph to a file named \p filename.
+ * \param nodeNames map used to translate node ids to human readable text.
+ * \param fileName file name where the output should be written.
+ */
+ void dumpDot(const QHash<int, QString>& nodeNames, const QString& fileName) const;
+
+ /**
+ * Topologically sort this graph.
+ * \return A collection with all nodes topologically sorted or an empty collection if a ciclic dependency was found.
+ */
+ QLinkedList<int> topologicalSort() const;
+private:
+
+ struct GraphPrivate;
+ GraphPrivate* m_d;
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/header_paths.h b/sources/shiboken2/ApiExtractor/header_paths.h
new file mode 100644
index 000000000..3bc26efe0
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/header_paths.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HEADER_PATHS_H
+#define HEADER_PATHS_H
+
+#include <QByteArray>
+#include <QList>
+#include <QString>
+
+class HeaderPath {
+public:
+ explicit HeaderPath(const QByteArray &p = QByteArray()) : path(p), m_isFramework(false) {}
+ explicit HeaderPath(const QString &s = QString(), bool isFramework = false) :
+ path(s.toLatin1()), m_isFramework(isFramework) {}
+
+ QByteArray path;
+ bool m_isFramework; // macOS framework path
+
+ static QByteArray includeOption(const HeaderPath &p, bool systemInclude = false)
+ {
+ QByteArray option;
+
+ if (p.m_isFramework)
+ option = QByteArrayLiteral("-F");
+ else if (systemInclude)
+ option = QByteArrayLiteral("-isystem");
+ else
+ option = QByteArrayLiteral("-I");
+
+ return option + p.path;
+ }
+};
+
+typedef QList<HeaderPath> HeaderPaths;
+
+#endif // HEADER_PATHS_H
diff --git a/sources/shiboken2/ApiExtractor/icecc.cmake b/sources/shiboken2/ApiExtractor/icecc.cmake
new file mode 100644
index 000000000..b2bf071aa
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/icecc.cmake
@@ -0,0 +1,11 @@
+include (CMakeForceCompiler)
+option(ENABLE_ICECC "Enable icecc checking, for distributed compilation")
+if (ENABLE_ICECC)
+ find_program(ICECC icecc)
+ if (ICECC)
+ message(STATUS "icecc found! Distributed compilation for all!! huhuhu.")
+ cmake_force_cxx_compiler(${ICECC} icecc)
+ else(ICECC)
+ message(FATAL_ERROR "icecc NOT found! re-run cmake without -DENABLE_ICECC")
+ endif(ICECC)
+endif(ENABLE_ICECC)
diff --git a/sources/shiboken2/ApiExtractor/include.cpp b/sources/shiboken2/ApiExtractor/include.cpp
new file mode 100644
index 000000000..deae2d2ac
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/include.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "include.h"
+#include <QDebug>
+#include <QDir>
+#include <QTextStream>
+#include <QHash>
+
+QString Include::toString() const
+{
+ if (m_type == IncludePath)
+ return QLatin1String("#include <") + m_name + QLatin1Char('>');
+ else if (m_type == LocalPath)
+ return QLatin1String("#include \"") + m_name + QLatin1Char('"');
+ else
+ return QLatin1String("import ") + m_name + QLatin1Char(';');
+}
+
+uint qHash(const Include& inc)
+{
+ return qHash(inc.m_name);
+}
+
+QTextStream& operator<<(QTextStream& out, const Include& include)
+{
+ if (include.isValid())
+ out << include.toString() << endl;
+ return out;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const Include &i)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "Include(";
+ if (i.isValid())
+ d << "type=" << i.type() << ", file=\"" << QDir::toNativeSeparators(i.name()) << '"';
+ else
+ d << "invalid";
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/ApiExtractor/include.h b/sources/shiboken2/ApiExtractor/include.h
new file mode 100644
index 000000000..dc4965e1a
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/include.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef INCLUDE_H
+#define INCLUDE_H
+
+#include <QString>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+class QTextStream;
+QT_END_NAMESPACE
+
+class Include
+{
+public:
+ enum IncludeType {
+ IncludePath,
+ LocalPath,
+ TargetLangImport
+ };
+
+ Include() : m_type(IncludePath) {}
+ Include(IncludeType t, const QString &nam) : m_type(t), m_name(nam) {};
+
+ bool isValid() const
+ {
+ return !m_name.isEmpty();
+ }
+
+ IncludeType type() const
+ {
+ return m_type;
+ }
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ QString toString() const;
+
+ bool operator<(const Include& other) const
+ {
+ return m_name < other.m_name;
+ }
+
+ bool operator==(const Include& other) const
+ {
+ return m_type == other.m_type && m_name == other.m_name;
+ }
+
+ friend uint qHash(const Include&);
+ private:
+ IncludeType m_type;
+ QString m_name;
+};
+
+uint qHash(const Include& inc);
+QTextStream& operator<<(QTextStream& out, const Include& include);
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const Include &i);
+#endif
+
+typedef QVector<Include> IncludeList;
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/merge.xsl b/sources/shiboken2/ApiExtractor/merge.xsl
new file mode 100644
index 000000000..d0b7eafa5
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/merge.xsl
@@ -0,0 +1,82 @@
+<?xml version="1.0"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0">
+ <xsl:output method="xml" indent="yes"/>
+ <xsl:param name="lang" />
+ <xsl:param name="source" />
+
+ <xsl:template match="processing-instruction()" />
+
+ <xsl:template match="/typesystem">
+ <xsl:copy>
+ <xsl:for-each select="@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:for-each select="document($source)/typesystem/@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:variable name="other" select="document($source)/typesystem/*[not(self::object-type | self::value-type | self::interface-type | self::namespace-type)]" />
+ <xsl:if test="$other">
+ <xsl:choose>
+ <xsl:when test="$lang != ''">
+ <xsl:element name="language">
+ <xsl:attribute name="name" ><xsl:value-of select="$lang" /></xsl:attribute>
+ <xsl:copy-of select="$other" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$other" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+
+ <xsl:apply-templates select="node()" />
+
+ </xsl:copy>
+ </xsl:template>
+
+
+
+ <xsl:template match="/typesystem/*[self::object-type | self::value-type | self::interface-type | self::namespace-type]">
+ <xsl:variable name="name" select="name()" />
+ <xsl:copy>
+ <xsl:for-each select="@*">
+ <xsl:copy>
+ <xsl:value-of select="." />
+ </xsl:copy>
+ </xsl:for-each>
+
+ <xsl:apply-templates select="node()" />
+
+ <xsl:variable name="other" select="document($source)/typesystem/*[name() = $name][@name = current()/@name]" />
+ <xsl:if test="$other">
+ <xsl:choose>
+ <xsl:when test="$lang != ''">
+ <xsl:element name="language">
+ <xsl:attribute name="name" ><xsl:value-of select="$lang" /></xsl:attribute>
+ <xsl:copy-of select="$other/node()" />
+ </xsl:element>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:copy-of select="$other/node()" />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:copy>
+ </xsl:template>
+
+ <!-- Plain identity transform. -->
+ <xsl:template match="@*|node()">
+ <xsl:copy>
+ <xsl:apply-templates select="@*"/>
+ <xsl:apply-templates select="node()"/>
+ </xsl:copy>
+ </xsl:template>
+
+</xsl:stylesheet>
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp
new file mode 100644
index 000000000..667e27344
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp
@@ -0,0 +1,1207 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "codemodel.h"
+#include <algorithm>
+#include <functional>
+#include <iostream>
+#include <QDebug>
+#include <QDir>
+
+// Predicate to find an item by name in a list of QSharedPointer<Item>
+template <class T> class ModelItemNamePredicate : public std::unary_function<bool, QSharedPointer<T> >
+{
+public:
+ explicit ModelItemNamePredicate(const QString &name) : m_name(name) {}
+ bool operator()(const QSharedPointer<T> &item) const { return item->name() == m_name; }
+
+private:
+ const QString m_name;
+};
+
+template <class T>
+static QSharedPointer<T> findModelItem(const QVector<QSharedPointer<T> > &list, const QString &name)
+{
+ typedef typename QVector<QSharedPointer<T> >::const_iterator It;
+ const It it = std::find_if(list.begin(), list.end(), ModelItemNamePredicate<T>(name));
+ return it != list.end() ? *it : QSharedPointer<T>();
+}
+
+// ---------------------------------------------------------------------------
+
+CodeModel::CodeModel() : m_globalNamespace(new _NamespaceModelItem(this))
+{
+}
+
+CodeModel::~CodeModel()
+{
+}
+
+NamespaceModelItem CodeModel::globalNamespace() const
+{
+ return m_globalNamespace;
+}
+
+void CodeModel::addFile(FileModelItem item)
+{
+ m_files.append(item);
+}
+
+FileModelItem CodeModel::findFile(const QString &name) const
+{
+ return findModelItem(m_files, name);
+}
+
+CodeModelItem CodeModel::findItem(const QStringList &qualifiedName, CodeModelItem scope) const
+{
+ for (int i = 0; i < qualifiedName.size(); ++i) {
+ // ### Extend to look for members etc too.
+ const QString &name = qualifiedName.at(i);
+
+ if (NamespaceModelItem ns = qSharedPointerDynamicCast<_NamespaceModelItem>(scope)) {
+ if (NamespaceModelItem tmp_ns = ns->findNamespace(name)) {
+ scope = tmp_ns;
+ continue;
+ }
+ }
+
+ if (ScopeModelItem ss = qSharedPointerDynamicCast<_ScopeModelItem>(scope)) {
+ if (ClassModelItem cs = ss->findClass(name)) {
+ scope = cs;
+ } else if (EnumModelItem es = ss->findEnum(name)) {
+ if (i == qualifiedName.size() - 1)
+ return es;
+ } else if (TypeDefModelItem tp = ss->findTypeDef(name)) {
+ if (i == qualifiedName.size() - 1)
+ return tp;
+ } else {
+ // If we don't find the name in the scope chain we
+ // need to return an empty item to indicate failure...
+ return CodeModelItem();
+ }
+ }
+ }
+
+ return scope;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const CodeModel *m)
+{
+ QDebugStateSaver s(d);
+ d.noquote();
+ d.nospace();
+ d << "CodeModel(";
+ if (m) {
+ const NamespaceModelItem globalNamespaceP = m->globalNamespace();
+ if (globalNamespaceP.data())
+ globalNamespaceP->formatDebug(d);
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+TypeInfo TypeInfo::combine(const TypeInfo &__lhs, const TypeInfo &__rhs)
+{
+ TypeInfo __result = __lhs;
+
+ __result.setConstant(__result.isConstant() || __rhs.isConstant());
+ __result.setVolatile(__result.isVolatile() || __rhs.isVolatile());
+ if (__rhs.referenceType() > __result.referenceType())
+ __result.setReferenceType(__rhs.referenceType());
+ __result.setIndirections(__result.indirections() + __rhs.indirections());
+ __result.setArrayElements(__result.arrayElements() + __rhs.arrayElements());
+
+ return __result;
+}
+
+TypeInfo TypeInfo::resolveType(TypeInfo const &__type, CodeModelItem __scope)
+{
+ CodeModel *__model = __scope->model();
+ Q_ASSERT(__model != 0);
+
+ return TypeInfo::resolveType(__model->findItem(__type.qualifiedName(), __scope), __type, __scope);
+}
+
+TypeInfo TypeInfo::resolveType(CodeModelItem __item, TypeInfo const &__type, CodeModelItem __scope)
+{
+ // Copy the type and replace with the proper qualified name. This
+ // only makes sence to do if we're actually getting a resolved
+ // type with a namespace. We only get this if the returned type
+ // has more than 2 entries in the qualified name... This test
+ // could be improved by returning if the type was found or not.
+ TypeInfo otherType(__type);
+ if (__item && __item->qualifiedName().size() > 1) {
+ otherType.setQualifiedName(__item->qualifiedName());
+ }
+
+ if (TypeDefModelItem __typedef = qSharedPointerDynamicCast<_TypeDefModelItem>(__item)) {
+ const TypeInfo combined = TypeInfo::combine(__typedef->type(), otherType);
+ const CodeModelItem nextItem = __scope->model()->findItem(combined.qualifiedName(), __scope);
+ if (!nextItem)
+ return combined;
+ // PYSIDE-362, prevent recursion on opaque structs like
+ // typedef struct xcb_connection_t xcb_connection_t;
+ if (nextItem.data() ==__item.data()) {
+ std::cerr << "** WARNING Bailing out recursion of " << __FUNCTION__
+ << "() on " << qPrintable(__type.qualifiedName().join(QLatin1String("::")))
+ << std::endl;
+ return otherType;
+ }
+ return resolveType(nextItem, combined, __scope);
+ }
+
+ return otherType;
+}
+
+QString TypeInfo::toString() const
+{
+ QString tmp;
+
+ tmp += m_qualifiedName.join(QLatin1String("::"));
+ if (isConstant())
+ tmp += QLatin1String(" const");
+
+ if (isVolatile())
+ tmp += QLatin1String(" volatile");
+
+ if (indirections())
+ tmp += QString(indirections(), QLatin1Char('*'));
+
+ switch (referenceType()) {
+ case NoReference:
+ break;
+ case LValueReference:
+ tmp += QLatin1Char('&');
+ break;
+ case RValueReference:
+ tmp += QLatin1String("&&");
+ break;
+ }
+
+ if (isFunctionPointer()) {
+ tmp += QLatin1String(" (*)(");
+ for (int i = 0; i < m_arguments.count(); ++i) {
+ if (i != 0)
+ tmp += QLatin1String(", ");
+
+ tmp += m_arguments.at(i).toString();
+ }
+ tmp += QLatin1Char(')');
+ }
+
+ for (const QString &elt : m_arrayElements) {
+ tmp += QLatin1Char('[');
+ tmp += elt;
+ tmp += QLatin1Char(']');
+ }
+
+ return tmp;
+}
+
+bool TypeInfo::operator==(const TypeInfo &other) const
+{
+ if (arrayElements().count() != other.arrayElements().count())
+ return false;
+
+#if defined (RXX_CHECK_ARRAY_ELEMENTS) // ### it'll break
+ for (int i = 0; i < arrayElements().count(); ++i) {
+ QString elt1 = arrayElements().at(i).trimmed();
+ QString elt2 = other.arrayElements().at(i).trimmed();
+
+ if (elt1 != elt2)
+ return false;
+ }
+#endif
+
+ return flags == other.flags
+ && m_qualifiedName == other.m_qualifiedName
+ && (!m_functionPointer || m_arguments == other.m_arguments);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class It>
+void formatSequence(QDebug &d, It i1, It i2, const char *separator=", ")
+{
+ for (It i = i1; i != i2; ++i) {
+ if (i != i1)
+ d << separator;
+ d << *i;
+ }
+}
+
+void TypeInfo::formatDebug(QDebug &d) const
+{
+ d << '"';
+ formatSequence(d, m_qualifiedName.begin(), m_qualifiedName.end(), "\", \"");
+ d << '"';
+ if (m_constant)
+ d << ", [const]";
+ if (m_volatile)
+ d << ", [volatile]";
+ if (m_indirections)
+ d << ", indirections=" << m_indirections;
+ switch (m_referenceType) {
+ case NoReference:
+ break;
+ case LValueReference:
+ d << ", [ref]";
+ break;
+ case RValueReference:
+ d << ", [rvalref]";
+ break;
+ }
+ if (m_functionPointer) {
+ d << ", function ptr(";
+ formatSequence(d, m_arguments.begin(), m_arguments.end());
+ d << ')';
+ }
+ if (!m_arrayElements.isEmpty()) {
+ d << ", array[" << m_arrayElements.size() << "][";
+ formatSequence(d, m_arrayElements.begin(), m_arrayElements.end());
+ d << ']';
+ }
+}
+
+QDebug operator<<(QDebug d, const TypeInfo &t)
+{
+ QDebugStateSaver s(d);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)
+ const int verbosity = d.verbosity();
+#else
+ const int verbosity = 0;
+#endif
+ d.noquote();
+ d.nospace();
+ d << "TypeInfo(";
+ if (verbosity > 2)
+ t.formatDebug(d);
+ else
+ d << t.toString();
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_CodeModelItem::_CodeModelItem(CodeModel *model, int kind)
+ : m_model(model),
+ m_kind(kind),
+ m_startLine(0),
+ m_startColumn(0),
+ m_endLine(0),
+ m_endColumn(0)
+{
+}
+
+_CodeModelItem::_CodeModelItem(CodeModel *model, const QString &name, int kind)
+ : m_model(model),
+ m_kind(kind),
+ m_startLine(0),
+ m_startColumn(0),
+ m_endLine(0),
+ m_endColumn(0),
+ m_name(name)
+{
+}
+
+_CodeModelItem::~_CodeModelItem()
+{
+}
+
+int _CodeModelItem::kind() const
+{
+ return m_kind;
+}
+
+QStringList _CodeModelItem::qualifiedName() const
+{
+ QStringList q = scope();
+
+ if (!name().isEmpty())
+ q += name();
+
+ return q;
+}
+
+QString _CodeModelItem::name() const
+{
+ return m_name;
+}
+
+void _CodeModelItem::setName(const QString &name)
+{
+ m_name = name;
+}
+
+QStringList _CodeModelItem::scope() const
+{
+ return m_scope;
+}
+
+void _CodeModelItem::setScope(const QStringList &scope)
+{
+ m_scope = scope;
+}
+
+QString _CodeModelItem::fileName() const
+{
+ return m_fileName;
+}
+
+void _CodeModelItem::setFileName(const QString &fileName)
+{
+ m_fileName = fileName;
+}
+
+FileModelItem _CodeModelItem::file() const
+{
+ return model()->findFile(fileName());
+}
+
+void _CodeModelItem::getStartPosition(int *line, int *column)
+{
+ *line = m_startLine;
+ *column = m_startColumn;
+}
+
+void _CodeModelItem::setStartPosition(int line, int column)
+{
+ m_startLine = line;
+ m_startColumn = column;
+}
+
+void _CodeModelItem::getEndPosition(int *line, int *column)
+{
+ *line = m_endLine;
+ *column = m_endColumn;
+}
+
+void _CodeModelItem::setEndPosition(int line, int column)
+{
+ m_endLine = line;
+ m_endColumn = column;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class It>
+static void formatPtrSequence(QDebug &d, It i1, It i2, const char *separator=", ")
+{
+ for (It i = i1; i != i2; ++i) {
+ if (i != i1)
+ d << separator;
+ d << i->data();
+ }
+}
+
+void _CodeModelItem::formatKind(QDebug &d, int k)
+{
+ switch (k) {
+ case Kind_Argument:
+ d << "ArgumentModelItem";
+ break;
+ case Kind_Class:
+ d << "ClassModelItem";
+ break;
+ case Kind_Enum:
+ d << "EnumModelItem";
+ break;
+ case Kind_Enumerator:
+ d << "EnumeratorModelItem";
+ break;
+ case Kind_File:
+ d << "FileModelItem";
+ break;
+ case Kind_Function:
+ d << "FunctionModelItem";
+ break;
+ case Kind_Member:
+ d << "MemberModelItem";
+ break;
+ case Kind_Namespace:
+ d << "NamespaceModelItem";
+ break;
+ case Kind_Variable:
+ d << "VariableModelItem";
+ break;
+ case Kind_Scope:
+ d << "ScopeModelItem";
+ break;
+ case Kind_TemplateParameter:
+ d << "TemplateParameter";
+ break;
+ case Kind_TypeDef:
+ d << "TypeDefModelItem";
+ break;
+ default:
+ d << "CodeModelItem";
+ break;
+ }
+}
+
+void _CodeModelItem::formatDebug(QDebug &d) const
+{
+ d << "(\"" << name() << '"';
+ if (!m_scope.isEmpty()) {
+ d << ", scope=";
+ formatSequence(d, m_scope.cbegin(), m_scope.cend(), "::");
+ }
+ if (!m_fileName.isEmpty()) {
+ d << ", file=\"" << QDir::toNativeSeparators(m_fileName);
+ if (m_startLine > 0)
+ d << ':' << m_startLine;
+ d << '"';
+ }
+}
+
+QDebug operator<<(QDebug d, const _CodeModelItem *t)
+{
+ QDebugStateSaver s(d);
+ d.noquote();
+ d.nospace();
+ if (!t) {
+ d << "CodeModelItem(0)";
+ return d;
+ }
+ _CodeModelItem::formatKind(d, t->kind());
+ t->formatDebug(d);
+ switch (t->kind()) {
+ case _CodeModelItem::Kind_Class:
+ d << " /* class " << t->name() << " */";
+ break;
+ case _CodeModelItem::Kind_Namespace:
+ d << " /* namespace " << t->name() << " */";
+ break;
+ }
+ d << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_ClassModelItem::~_ClassModelItem()
+{
+}
+
+QStringList _ClassModelItem::baseClasses() const
+{
+ return m_baseClasses;
+}
+
+void _ClassModelItem::setBaseClasses(const QStringList &baseClasses)
+{
+ m_baseClasses = baseClasses;
+}
+
+TemplateParameterList _ClassModelItem::templateParameters() const
+{
+ return m_templateParameters;
+}
+
+void _ClassModelItem::setTemplateParameters(const TemplateParameterList &templateParameters)
+{
+ m_templateParameters = templateParameters;
+}
+
+void _ClassModelItem::addBaseClass(const QString &baseClass)
+{
+ m_baseClasses.append(baseClass);
+}
+
+bool _ClassModelItem::extendsClass(const QString &name) const
+{
+ return m_baseClasses.contains(name);
+}
+
+void _ClassModelItem::setClassType(CodeModel::ClassType type)
+{
+ m_classType = type;
+}
+
+CodeModel::ClassType _ClassModelItem::classType() const
+{
+ return m_classType;
+}
+
+void _ClassModelItem::addPropertyDeclaration(const QString &propertyDeclaration)
+{
+ m_propertyDeclarations << propertyDeclaration;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class List>
+static void formatModelItemList(QDebug &d, const char *prefix, const List &l,
+ const char *separator = ", ")
+{
+ if (const int size = l.size()) {
+ d << prefix << '[' << size << "](";
+ for (int i = 0; i < size; ++i) {
+ if (i)
+ d << separator;
+ l.at(i)->formatDebug(d);
+ }
+ d << ')';
+ }
+}
+
+void _ClassModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ if (!m_baseClasses.isEmpty())
+ d << ", inherits=" << m_baseClasses;
+ formatModelItemList(d, ", templateParameters=", m_templateParameters);
+ formatScopeItemsDebug(d);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+FunctionModelItem _ScopeModelItem::declaredFunction(FunctionModelItem item)
+{
+ for (const FunctionModelItem &fun : qAsConst(m_functions)) {
+ if (fun->name() == item->name() && fun->isSimilar(item))
+ return fun;
+
+ }
+ return FunctionModelItem();
+}
+
+_ScopeModelItem::~_ScopeModelItem()
+{
+}
+
+void _ScopeModelItem::addEnumsDeclaration(const QString &enumsDeclaration)
+{
+ m_enumsDeclarations << enumsDeclaration;
+}
+
+void _ScopeModelItem::addClass(ClassModelItem item)
+{
+ m_classes.append(item);
+}
+
+void _ScopeModelItem::addFunction(FunctionModelItem item)
+{
+ m_functions.append(item);
+}
+
+void _ScopeModelItem::addVariable(VariableModelItem item)
+{
+ m_variables.append(item);
+}
+
+void _ScopeModelItem::addTypeDef(TypeDefModelItem item)
+{
+ m_typeDefs.append(item);
+}
+
+void _ScopeModelItem::addEnum(EnumModelItem item)
+{
+ m_enums.append(item);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+template <class Hash>
+static void formatScopeHash(QDebug &d, const char *prefix, const Hash &h,
+ const char *separator = ", ",
+ bool trailingNewLine = false)
+{
+ typedef typename Hash::ConstIterator HashIterator;
+ if (!h.isEmpty()) {
+ d << prefix << '[' << h.size() << "](";
+ const HashIterator begin = h.begin();
+ const HashIterator end = h.end();
+ for (HashIterator it = begin; it != end; ++it) { // Omit the names as they are repeated
+ if (it != begin)
+ d << separator;
+ d << it.value().data();
+ }
+ d << ')';
+ if (trailingNewLine)
+ d << '\n';
+ }
+}
+
+template <class List>
+static void formatScopeList(QDebug &d, const char *prefix, const List &l,
+ const char *separator = ", ",
+ bool trailingNewLine = false)
+{
+ if (!l.isEmpty()) {
+ d << prefix << '[' << l.size() << "](";
+ formatPtrSequence(d, l.begin(), l.end(), separator);
+ d << ')';
+ if (trailingNewLine)
+ d << '\n';
+ }
+}
+
+void _ScopeModelItem::formatScopeItemsDebug(QDebug &d) const
+{
+ formatScopeList(d, ", classes=", m_classes, "\n", true);
+ formatScopeList(d, ", enums=", m_enums, "\n", true);
+ formatScopeList(d, ", aliases=", m_typeDefs, "\n", true);
+ formatScopeList(d, ", functions=", m_functions, "\n", true);
+ formatScopeList(d, ", variables=", m_variables);
+}
+
+void _ScopeModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ formatScopeItemsDebug(d);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+namespace {
+// Predicate to match a non-template class name against the class list.
+// "Vector" should match "Vector" as well as "Vector<T>" (as seen for methods
+// from within the class "Vector").
+class ClassNamePredicate : public std::unary_function<bool, ClassModelItem>
+{
+public:
+ explicit ClassNamePredicate(const QString &name) : m_name(name) {}
+ bool operator()(const ClassModelItem &item) const
+ {
+ const QString &itemName = item->name();
+ if (!itemName.startsWith(m_name))
+ return false;
+ return itemName.size() == m_name.size() || itemName.at(m_name.size()) == QLatin1Char('<');
+ }
+
+private:
+ const QString m_name;
+};
+} // namespace
+
+ClassModelItem _ScopeModelItem::findClass(const QString &name) const
+{
+ // A fully qualified template is matched by name only
+ const ClassList::const_iterator it = name.contains(QLatin1Char('<'))
+ ? std::find_if(m_classes.begin(), m_classes.end(), ModelItemNamePredicate<_ClassModelItem>(name))
+ : std::find_if(m_classes.begin(), m_classes.end(), ClassNamePredicate(name));
+ return it != m_classes.end() ? *it : ClassModelItem();
+}
+
+VariableModelItem _ScopeModelItem::findVariable(const QString &name) const
+{
+ return findModelItem(m_variables, name);
+}
+
+TypeDefModelItem _ScopeModelItem::findTypeDef(const QString &name) const
+{
+ return findModelItem(m_typeDefs, name);
+}
+
+EnumModelItem _ScopeModelItem::findEnum(const QString &name) const
+{
+ return findModelItem(m_enums, name);
+}
+
+FunctionList _ScopeModelItem::findFunctions(const QString &name) const
+{
+ FunctionList result;
+ for (const FunctionModelItem &func : m_functions) {
+ if (func->name() == name)
+ result.append(func);
+ }
+ return result;
+}
+
+// ---------------------------------------------------------------------------
+_NamespaceModelItem::~_NamespaceModelItem()
+{
+}
+
+QSet<NamespaceModelItem> _NamespaceModelItem::uniqueNamespaces() const
+{
+ QSet<NamespaceModelItem> result;
+ for (const NamespaceModelItem &n : m_namespaces)
+ result.insert(n);
+ return result;
+}
+
+void _NamespaceModelItem::addNamespace(NamespaceModelItem item)
+{
+ m_namespaces.append(item);
+}
+
+NamespaceModelItem _NamespaceModelItem::findNamespace(const QString &name) const
+{
+ return findModelItem(m_namespaces, name);
+}
+
+_FileModelItem::~_FileModelItem()
+{
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _NamespaceModelItem::formatDebug(QDebug &d) const
+{
+ _ScopeModelItem::formatDebug(d);
+ formatScopeList(d, ", namespaces=", m_namespaces);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_ArgumentModelItem::~_ArgumentModelItem()
+{
+}
+
+TypeInfo _ArgumentModelItem::type() const
+{
+ return m_type;
+}
+
+void _ArgumentModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+bool _ArgumentModelItem::defaultValue() const
+{
+ return m_defaultValue;
+}
+
+void _ArgumentModelItem::setDefaultValue(bool defaultValue)
+{
+ m_defaultValue = defaultValue;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _ArgumentModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", type=" << m_type;
+ if (m_defaultValue)
+ d << ", defaultValue=\"" << m_defaultValueExpression << '"';
+}
+#endif // !QT_NO_DEBUG_STREAM
+// ---------------------------------------------------------------------------
+_FunctionModelItem::~_FunctionModelItem()
+{
+}
+
+bool _FunctionModelItem::isSimilar(FunctionModelItem other) const
+{
+ if (name() != other->name())
+ return false;
+
+ if (isConstant() != other->isConstant())
+ return false;
+
+ if (isVariadics() != other->isVariadics())
+ return false;
+
+ if (arguments().count() != other->arguments().count())
+ return false;
+
+ // ### check the template parameters
+
+ for (int i = 0; i < arguments().count(); ++i) {
+ ArgumentModelItem arg1 = arguments().at(i);
+ ArgumentModelItem arg2 = other->arguments().at(i);
+
+ if (arg1->type() != arg2->type())
+ return false;
+ }
+
+ return true;
+}
+
+ArgumentList _FunctionModelItem::arguments() const
+{
+ return m_arguments;
+}
+
+void _FunctionModelItem::addArgument(ArgumentModelItem item)
+{
+ m_arguments.append(item);
+}
+
+CodeModel::FunctionType _FunctionModelItem::functionType() const
+{
+ return m_functionType;
+}
+
+void _FunctionModelItem::setFunctionType(CodeModel::FunctionType functionType)
+{
+ m_functionType = functionType;
+}
+
+bool _FunctionModelItem::isVariadics() const
+{
+ return m_isVariadics;
+}
+
+void _FunctionModelItem::setVariadics(bool isVariadics)
+{
+ m_isVariadics = isVariadics;
+}
+
+bool _FunctionModelItem::isVirtual() const
+{
+ return m_isVirtual;
+}
+
+void _FunctionModelItem::setVirtual(bool isVirtual)
+{
+ m_isVirtual = isVirtual;
+}
+
+bool _FunctionModelItem::isInline() const
+{
+ return m_isInline;
+}
+
+void _FunctionModelItem::setInline(bool isInline)
+{
+ m_isInline = isInline;
+}
+
+bool _FunctionModelItem::isExplicit() const
+{
+ return m_isExplicit;
+}
+
+void _FunctionModelItem::setExplicit(bool isExplicit)
+{
+ m_isExplicit = isExplicit;
+}
+
+bool _FunctionModelItem::isAbstract() const
+{
+ return m_isAbstract;
+}
+
+void _FunctionModelItem::setAbstract(bool isAbstract)
+{
+ m_isAbstract = isAbstract;
+}
+
+// Qt
+bool _FunctionModelItem::isInvokable() const
+{
+ return m_isInvokable;
+}
+
+void _FunctionModelItem::setInvokable(bool isInvokable)
+{
+ m_isInvokable = isInvokable;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _FunctionModelItem::formatDebug(QDebug &d) const
+{
+ _MemberModelItem::formatDebug(d);
+ d << ", type=" << m_functionType;
+ if (m_isInline)
+ d << " [inline]";
+ if (m_isAbstract)
+ d << " [abstract]";
+ if (m_isExplicit)
+ d << " [explicit]";
+ if (m_isInvokable)
+ d << " [invokable]";
+ formatModelItemList(d, ", arguments=", m_arguments);
+ if (m_isVariadics)
+ d << ",...";
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+TypeInfo _TypeDefModelItem::type() const
+{
+ return m_type;
+}
+
+void _TypeDefModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _TypeDefModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", type=" << m_type;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+CodeModel::AccessPolicy _EnumModelItem::accessPolicy() const
+{
+ return m_accessPolicy;
+}
+
+_EnumModelItem::~_EnumModelItem()
+{
+}
+
+void _EnumModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy)
+{
+ m_accessPolicy = accessPolicy;
+}
+
+EnumeratorList _EnumModelItem::enumerators() const
+{
+ return m_enumerators;
+}
+
+void _EnumModelItem::addEnumerator(EnumeratorModelItem item)
+{
+ m_enumerators.append(item);
+}
+
+bool _EnumModelItem::isAnonymous() const
+{
+ return m_anonymous;
+}
+
+void _EnumModelItem::setAnonymous(bool anonymous)
+{
+ m_anonymous = anonymous;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _EnumModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ if (m_anonymous)
+ d << " (anonymous)";
+ formatModelItemList(d, ", enumerators=", m_enumerators);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_EnumeratorModelItem::~_EnumeratorModelItem()
+{
+}
+
+QString _EnumeratorModelItem::value() const
+{
+ return m_value;
+}
+
+void _EnumeratorModelItem::setValue(const QString &value)
+{
+ m_value = value;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _EnumeratorModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ if (!m_value.isEmpty())
+ d << ", value=\"" << m_value << '"';
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+_TemplateParameterModelItem::~_TemplateParameterModelItem()
+{
+}
+
+TypeInfo _TemplateParameterModelItem::type() const
+{
+ return m_type;
+}
+
+void _TemplateParameterModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+bool _TemplateParameterModelItem::defaultValue() const
+{
+ return m_defaultValue;
+}
+
+void _TemplateParameterModelItem::setDefaultValue(bool defaultValue)
+{
+ m_defaultValue = defaultValue;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _TemplateParameterModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ d << ", type=" << m_type;
+ if (m_defaultValue)
+ d << " [defaultValue]";
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// ---------------------------------------------------------------------------
+TypeInfo _MemberModelItem::type() const
+{
+ return m_type;
+}
+
+void _MemberModelItem::setType(const TypeInfo &type)
+{
+ m_type = type;
+}
+
+CodeModel::AccessPolicy _MemberModelItem::accessPolicy() const
+{
+ return m_accessPolicy;
+}
+
+_MemberModelItem::~_MemberModelItem()
+{
+}
+
+void _MemberModelItem::setAccessPolicy(CodeModel::AccessPolicy accessPolicy)
+{
+ m_accessPolicy = accessPolicy;
+}
+
+bool _MemberModelItem::isStatic() const
+{
+ return m_isStatic;
+}
+
+void _MemberModelItem::setStatic(bool isStatic)
+{
+ m_isStatic = isStatic;
+}
+
+bool _MemberModelItem::isConstant() const
+{
+ return m_isConstant;
+}
+
+void _MemberModelItem::setConstant(bool isConstant)
+{
+ m_isConstant = isConstant;
+}
+
+bool _MemberModelItem::isVolatile() const
+{
+ return m_isVolatile;
+}
+
+void _MemberModelItem::setVolatile(bool isVolatile)
+{
+ m_isVolatile = isVolatile;
+}
+
+bool _MemberModelItem::isAuto() const
+{
+ return m_isAuto;
+}
+
+void _MemberModelItem::setAuto(bool isAuto)
+{
+ m_isAuto = isAuto;
+}
+
+bool _MemberModelItem::isFriend() const
+{
+ return m_isFriend;
+}
+
+void _MemberModelItem::setFriend(bool isFriend)
+{
+ m_isFriend = isFriend;
+}
+
+bool _MemberModelItem::isRegister() const
+{
+ return m_isRegister;
+}
+
+void _MemberModelItem::setRegister(bool isRegister)
+{
+ m_isRegister = isRegister;
+}
+
+bool _MemberModelItem::isExtern() const
+{
+ return m_isExtern;
+}
+
+void _MemberModelItem::setExtern(bool isExtern)
+{
+ m_isExtern = isExtern;
+}
+
+bool _MemberModelItem::isMutable() const
+{
+ return m_isMutable;
+}
+
+void _MemberModelItem::setMutable(bool isMutable)
+{
+ m_isMutable = isMutable;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void _MemberModelItem::formatDebug(QDebug &d) const
+{
+ _CodeModelItem::formatDebug(d);
+ switch (m_accessPolicy) {
+ case CodeModel::Public:
+ d << ", public";
+ break;
+ case CodeModel::Protected:
+ d << ", protected";
+ break;
+ case CodeModel::Private:
+ d << ", private";
+ break;
+ }
+ d << ", type=";
+ if (m_isConstant)
+ d << "const ";
+ if (m_isVolatile)
+ d << "volatile ";
+ if (m_isStatic)
+ d << "static ";
+ if (m_isAuto)
+ d << "auto ";
+ if (m_isFriend)
+ d << "friend ";
+ if (m_isRegister)
+ d << "register ";
+ if (m_isExtern)
+ d << "extern ";
+ if (m_isMutable)
+ d << "mutable ";
+ d << m_type;
+ formatScopeList(d, ", templateParameters", m_templateParameters);
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
+
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.h b/sources/shiboken2/ApiExtractor/parser/codemodel.h
new file mode 100644
index 000000000..ea16e6912
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h
@@ -0,0 +1,687 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef CODEMODEL_H
+#define CODEMODEL_H
+
+#include "codemodel_fwd.h"
+#include "codemodel_enums.h"
+
+#include <QtCore/QHash>
+#include <QtCore/QSet>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+#define DECLARE_MODEL_NODE(k) \
+ enum { __node_kind = Kind_##k };
+
+class CodeModel
+{
+public:
+ enum AccessPolicy {
+ Public,
+ Protected,
+ Private
+ };
+
+ enum FunctionType {
+ Normal,
+ Signal,
+ Slot
+ };
+
+ enum ClassType {
+ Class,
+ Struct,
+ Union
+ };
+
+public:
+ CodeModel();
+ virtual ~CodeModel();
+
+ FileList files() const { return m_files; }
+ NamespaceModelItem globalNamespace() const;
+
+ void addFile(FileModelItem item);
+ FileModelItem findFile(const QString &name) const;
+
+ CodeModelItem findItem(const QStringList &qualifiedName, CodeModelItem scope) const;
+
+private:
+ FileList m_files;
+ NamespaceModelItem m_globalNamespace;
+
+private:
+ CodeModel(const CodeModel &other);
+ void operator = (const CodeModel &other);
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const CodeModel *m);
+#endif
+
+class TypeInfo
+{
+public:
+ TypeInfo() : flags(0), m_referenceType(NoReference) {}
+
+ QStringList qualifiedName() const
+ {
+ return m_qualifiedName;
+ }
+
+ void setQualifiedName(const QStringList &qualified_name)
+ {
+ m_qualifiedName = qualified_name;
+ }
+
+ bool isConstant() const
+ {
+ return m_constant;
+ }
+
+ void setConstant(bool is)
+ {
+ m_constant = is;
+ }
+
+ bool isVolatile() const
+ {
+ return m_volatile;
+ }
+
+ void setVolatile(bool is)
+ {
+ m_volatile = is;
+ }
+
+ ReferenceType referenceType() const { return m_referenceType; }
+ void setReferenceType(ReferenceType r) { m_referenceType = r; }
+
+ int indirections() const
+ {
+ return m_indirections;
+ }
+
+ void setIndirections(int indirections)
+ {
+ m_indirections = indirections;
+ }
+
+ bool isFunctionPointer() const
+ {
+ return m_functionPointer;
+ }
+ void setFunctionPointer(bool is)
+ {
+ m_functionPointer = is;
+ }
+
+ QStringList arrayElements() const
+ {
+ return m_arrayElements;
+ }
+ void setArrayElements(const QStringList &arrayElements)
+ {
+ m_arrayElements = arrayElements;
+ }
+
+ QVector<TypeInfo> arguments() const { return m_arguments; }
+
+ void setArguments(const QVector<TypeInfo> &arguments);
+
+ void addArgument(const TypeInfo &arg)
+ {
+ m_arguments.append(arg);
+ }
+
+ bool operator==(const TypeInfo &other) const;
+
+ bool operator!=(const TypeInfo &other) const
+ {
+ return !(*this == other);
+ }
+
+ // ### arrays and templates??
+
+ QString toString() const;
+
+ static TypeInfo combine(const TypeInfo &__lhs, const TypeInfo &__rhs);
+ static TypeInfo resolveType(TypeInfo const &__type, CodeModelItem __scope);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+
+private:
+ static TypeInfo resolveType(CodeModelItem item, TypeInfo const &__type, CodeModelItem __scope);
+
+ QStringList m_qualifiedName;
+ QStringList m_arrayElements;
+ QVector<TypeInfo> m_arguments;
+
+ union {
+ uint flags;
+
+ struct {
+ uint m_constant: 1;
+ uint m_volatile: 1;
+ uint m_functionPointer: 1;
+ uint m_indirections: 6;
+ uint m_padding: 23;
+ };
+ };
+
+ ReferenceType m_referenceType;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeInfo &t);
+#endif
+
+class _CodeModelItem
+{
+ Q_DISABLE_COPY(_CodeModelItem)
+public:
+ enum Kind {
+ /* These are bit-flags resembling inheritance */
+ Kind_Scope = 0x1,
+ Kind_Namespace = 0x2 | Kind_Scope,
+ Kind_Member = 0x4,
+ Kind_Function = 0x8 | Kind_Member,
+ KindMask = 0xf,
+
+ /* These are for classes that are not inherited from */
+ FirstKind = 0x8,
+ Kind_Argument = 1 << FirstKind,
+ Kind_Class = 2 << FirstKind | Kind_Scope,
+ Kind_Enum = 3 << FirstKind,
+ Kind_Enumerator = 4 << FirstKind,
+ Kind_File = 5 << FirstKind | Kind_Namespace,
+ Kind_TemplateParameter = 7 << FirstKind,
+ Kind_TypeDef = 8 << FirstKind,
+ Kind_Variable = 9 << FirstKind | Kind_Member
+ };
+
+public:
+ virtual ~_CodeModelItem();
+
+ int kind() const;
+
+ QStringList qualifiedName() const;
+
+ QString name() const;
+ void setName(const QString &name);
+
+ QStringList scope() const;
+ void setScope(const QStringList &scope);
+
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+ FileModelItem file() const;
+
+ void getStartPosition(int *line, int *column);
+ void setStartPosition(int line, int column);
+
+ void getEndPosition(int *line, int *column);
+ void setEndPosition(int line, int column);
+
+ inline CodeModel *model() const { return m_model; }
+
+#ifndef QT_NO_DEBUG_STREAM
+ static void formatKind(QDebug &d, int k);
+ virtual void formatDebug(QDebug &d) const;
+#endif
+
+protected:
+ explicit _CodeModelItem(CodeModel *model, int kind);
+ explicit _CodeModelItem(CodeModel *model, const QString &name, int kind);
+
+private:
+ CodeModel *m_model;
+ int m_kind;
+ int m_startLine;
+ int m_startColumn;
+ int m_endLine;
+ int m_endColumn;
+ QString m_name;
+ QString m_fileName;
+ QStringList m_scope;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const _CodeModelItem *t);
+#endif
+
+class _ScopeModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Scope)
+
+ ~_ScopeModelItem();
+
+ ClassList classes() const { return m_classes; }
+ EnumList enums() const { return m_enums; }
+ inline FunctionList functions() const { return m_functions; }
+ TypeDefList typeDefs() const { return m_typeDefs; }
+ VariableList variables() const { return m_variables; }
+
+ void addClass(ClassModelItem item);
+ void addEnum(EnumModelItem item);
+ void addFunction(FunctionModelItem item);
+ void addTypeDef(TypeDefModelItem item);
+ void addVariable(VariableModelItem item);
+
+ ClassModelItem findClass(const QString &name) const;
+ EnumModelItem findEnum(const QString &name) const;
+ FunctionList findFunctions(const QString &name) const;
+ TypeDefModelItem findTypeDef(const QString &name) const;
+ VariableModelItem findVariable(const QString &name) const;
+
+ void addEnumsDeclaration(const QString &enumsDeclaration);
+ QStringList enumsDeclarations() const { return m_enumsDeclarations; }
+
+ FunctionModelItem declaredFunction(FunctionModelItem item);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+protected:
+ explicit _ScopeModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind) {}
+ explicit _ScopeModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _CodeModelItem(model, name, kind) {}
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatScopeItemsDebug(QDebug &d) const;
+#endif
+
+private:
+ ClassList m_classes;
+ EnumList m_enums;
+ TypeDefList m_typeDefs;
+ VariableList m_variables;
+ FunctionList m_functions;
+
+private:
+ QStringList m_enumsDeclarations;
+};
+
+class _ClassModelItem: public _ScopeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Class)
+
+ explicit _ClassModelItem(CodeModel *model, int kind = __node_kind)
+ : _ScopeModelItem(model, kind), m_classType(CodeModel::Class) {}
+ explicit _ClassModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _ScopeModelItem(model, name, kind), m_classType(CodeModel::Class) {}
+ ~_ClassModelItem();
+
+ QStringList baseClasses() const;
+
+ void setBaseClasses(const QStringList &baseClasses);
+ void addBaseClass(const QString &baseClass);
+
+ TemplateParameterList templateParameters() const;
+ void setTemplateParameters(const TemplateParameterList &templateParameters);
+
+ bool extendsClass(const QString &name) const;
+
+ void setClassType(CodeModel::ClassType type);
+ CodeModel::ClassType classType() const;
+
+ void addPropertyDeclaration(const QString &propertyDeclaration);
+ QStringList propertyDeclarations() const { return m_propertyDeclarations; }
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ QStringList m_baseClasses;
+ TemplateParameterList m_templateParameters;
+ CodeModel::ClassType m_classType;
+
+ QStringList m_propertyDeclarations;
+};
+
+class _NamespaceModelItem: public _ScopeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Namespace)
+
+ explicit _NamespaceModelItem(CodeModel *model, int kind = __node_kind)
+ : _ScopeModelItem(model, kind) {}
+ explicit _NamespaceModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _ScopeModelItem(model, name, kind) {}
+ ~_NamespaceModelItem();
+
+ NamespaceList namespaces() const { return m_namespaces; }
+ QSet<NamespaceModelItem> uniqueNamespaces() const;
+
+ void addNamespace(NamespaceModelItem item);
+
+ NamespaceModelItem findNamespace(const QString &name) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ NamespaceList m_namespaces;
+};
+
+class _FileModelItem: public _NamespaceModelItem
+{
+public:
+ DECLARE_MODEL_NODE(File)
+
+ explicit _FileModelItem(CodeModel *model, int kind = __node_kind)
+ : _NamespaceModelItem(model, kind) {}
+ explicit _FileModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _NamespaceModelItem(model, name, kind) {}
+ ~_FileModelItem();
+};
+
+class _ArgumentModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Argument)
+
+ explicit _ArgumentModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind), m_defaultValue(false) {}
+ explicit _ArgumentModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _CodeModelItem(model, name, kind), m_defaultValue(false) {}
+ ~_ArgumentModelItem();
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+ bool defaultValue() const;
+ void setDefaultValue(bool defaultValue);
+
+ QString defaultValueExpression() const { return m_defaultValueExpression; }
+ void setDefaultValueExpression(const QString &expr) { m_defaultValueExpression = expr; }
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TypeInfo m_type;
+ QString m_defaultValueExpression;
+ bool m_defaultValue;
+};
+
+class _MemberModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Member)
+
+ explicit _MemberModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind), m_accessPolicy(CodeModel::Public), m_flags(0) {}
+ explicit _MemberModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _CodeModelItem(model, name, kind), m_accessPolicy(CodeModel::Public), m_flags(0) {}
+ ~_MemberModelItem();
+
+ bool isConstant() const;
+ void setConstant(bool isConstant);
+
+ bool isVolatile() const;
+ void setVolatile(bool isVolatile);
+
+ bool isStatic() const;
+ void setStatic(bool isStatic);
+
+ bool isAuto() const;
+ void setAuto(bool isAuto);
+
+ bool isFriend() const;
+ void setFriend(bool isFriend);
+
+ bool isRegister() const;
+ void setRegister(bool isRegister);
+
+ bool isExtern() const;
+ void setExtern(bool isExtern);
+
+ bool isMutable() const;
+ void setMutable(bool isMutable);
+
+ CodeModel::AccessPolicy accessPolicy() const;
+ void setAccessPolicy(CodeModel::AccessPolicy accessPolicy);
+
+ TemplateParameterList templateParameters() const { return m_templateParameters; }
+ void setTemplateParameters(const TemplateParameterList &templateParameters) { m_templateParameters = templateParameters; }
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TemplateParameterList m_templateParameters;
+ TypeInfo m_type;
+ CodeModel::AccessPolicy m_accessPolicy;
+ union {
+ struct {
+ uint m_isConstant: 1;
+ uint m_isVolatile: 1;
+ uint m_isStatic: 1;
+ uint m_isAuto: 1;
+ uint m_isFriend: 1;
+ uint m_isRegister: 1;
+ uint m_isExtern: 1;
+ uint m_isMutable: 1;
+ };
+ uint m_flags;
+ };
+
+};
+
+class _FunctionModelItem: public _MemberModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Function)
+
+ explicit _FunctionModelItem(CodeModel *model, int kind = __node_kind)
+ : _MemberModelItem(model, kind), m_functionType(CodeModel::Normal), m_flags(0) {}
+ explicit _FunctionModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _MemberModelItem(model, name, kind), m_functionType(CodeModel::Normal), m_flags(0) {}
+ ~_FunctionModelItem();
+
+ ArgumentList arguments() const;
+
+ void addArgument(ArgumentModelItem item);
+
+ CodeModel::FunctionType functionType() const;
+ void setFunctionType(CodeModel::FunctionType functionType);
+
+ bool isVirtual() const;
+ void setVirtual(bool isVirtual);
+
+ bool isInline() const;
+ void setInline(bool isInline);
+
+ bool isExplicit() const;
+ void setExplicit(bool isExplicit);
+
+ bool isInvokable() const; // Qt
+ void setInvokable(bool isInvokable); // Qt
+
+ bool isAbstract() const;
+ void setAbstract(bool isAbstract);
+
+ bool isVariadics() const;
+ void setVariadics(bool isVariadics);
+
+ bool isSimilar(FunctionModelItem other) const;
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ ArgumentList m_arguments;
+ CodeModel::FunctionType m_functionType;
+ union {
+ struct {
+ uint m_isVirtual: 1;
+ uint m_isInline: 1;
+ uint m_isAbstract: 1;
+ uint m_isExplicit: 1;
+ uint m_isVariadics: 1;
+ uint m_isInvokable : 1; // Qt
+ };
+ uint m_flags;
+ };
+};
+
+class _VariableModelItem: public _MemberModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Variable)
+
+ explicit _VariableModelItem(CodeModel *model, int kind = __node_kind)
+ : _MemberModelItem(model, kind) {}
+ explicit _VariableModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _MemberModelItem(model, name, kind) {}
+};
+
+class _TypeDefModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(TypeDef)
+
+ explicit _TypeDefModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind) {}
+ explicit _TypeDefModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _CodeModelItem(model, name, kind) {}
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TypeInfo m_type;
+};
+
+class _EnumModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Enum)
+
+ explicit _EnumModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind), m_accessPolicy(CodeModel::Public), m_anonymous(false) {}
+ explicit _EnumModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _CodeModelItem(model, name, kind), m_accessPolicy(CodeModel::Public), m_anonymous(false) {}
+ ~_EnumModelItem();
+
+ CodeModel::AccessPolicy accessPolicy() const;
+ void setAccessPolicy(CodeModel::AccessPolicy accessPolicy);
+
+ EnumeratorList enumerators() const;
+ void addEnumerator(EnumeratorModelItem item);
+ bool isAnonymous() const;
+ void setAnonymous(bool anonymous);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ CodeModel::AccessPolicy m_accessPolicy;
+ EnumeratorList m_enumerators;
+ bool m_anonymous;
+};
+
+class _EnumeratorModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(Enumerator)
+
+ explicit _EnumeratorModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind) {}
+ explicit _EnumeratorModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _CodeModelItem(model, name, kind) {}
+ ~_EnumeratorModelItem();
+
+ QString value() const;
+ void setValue(const QString &value);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ QString m_value;
+};
+
+class _TemplateParameterModelItem: public _CodeModelItem
+{
+public:
+ DECLARE_MODEL_NODE(TemplateParameter)
+
+ explicit _TemplateParameterModelItem(CodeModel *model, int kind = __node_kind)
+ : _CodeModelItem(model, kind), m_defaultValue(false) {}
+ explicit _TemplateParameterModelItem(CodeModel *model, const QString &name, int kind = __node_kind)
+ : _CodeModelItem(model, name, kind), m_defaultValue(false) {}
+ ~_TemplateParameterModelItem();
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+
+ bool defaultValue() const;
+ void setDefaultValue(bool defaultValue);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const override;
+#endif
+
+private:
+ TypeInfo m_type;
+ bool m_defaultValue;
+};
+
+#endif // CODEMODEL_H
+
+// kate: space-indent on; indent-width 2; replace-tabs on;
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h
new file mode 100644
index 000000000..aa8b051d8
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel_enums.h
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CODEMODEL_ENUMS_H
+#define CODEMODEL_ENUMS_H
+
+enum ReferenceType {
+ NoReference,
+ LValueReference,
+ RValueReference
+};
+
+#endif // CODEMODEL_ENUMS_H
diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h b/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h
new file mode 100644
index 000000000..d5a9f2850
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/parser/codemodel_fwd.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2002-2005 Roberto Raggi <roberto@kdevelop.org>
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef CODEMODEL_FWD_H
+#define CODEMODEL_FWD_H
+
+#include <QtCore/QVector>
+#include <QtCore/QSharedPointer>
+
+// forward declarations
+class CodeModel;
+class _ArgumentModelItem;
+class _ClassModelItem;
+class _CodeModelItem;
+class _EnumModelItem;
+class _EnumeratorModelItem;
+class _FileModelItem;
+class _FunctionModelItem;
+class _NamespaceModelItem;
+class _ScopeModelItem;
+class _TemplateParameterModelItem;
+class _TypeDefModelItem;
+class _VariableModelItem;
+class _MemberModelItem;
+class TypeInfo;
+
+typedef QSharedPointer<_ArgumentModelItem> ArgumentModelItem;
+typedef QSharedPointer<_ClassModelItem> ClassModelItem;
+typedef QSharedPointer<_CodeModelItem> CodeModelItem;
+typedef QSharedPointer<_EnumModelItem> EnumModelItem;
+typedef QSharedPointer<_EnumeratorModelItem> EnumeratorModelItem;
+typedef QSharedPointer<_FileModelItem> FileModelItem;
+typedef QSharedPointer<_FunctionModelItem> FunctionModelItem;
+typedef QSharedPointer<_NamespaceModelItem> NamespaceModelItem;
+typedef QSharedPointer<_ScopeModelItem> ScopeModelItem;
+typedef QSharedPointer<_TemplateParameterModelItem> TemplateParameterModelItem;
+typedef QSharedPointer<_TypeDefModelItem> TypeDefModelItem;
+typedef QSharedPointer<_VariableModelItem> VariableModelItem;
+typedef QSharedPointer<_MemberModelItem> MemberModelItem;
+
+typedef QVector<ArgumentModelItem> ArgumentList;
+typedef QVector<ClassModelItem> ClassList;
+typedef QVector<CodeModelItem> ItemList;
+typedef QVector<EnumModelItem> EnumList;
+typedef QVector<EnumeratorModelItem> EnumeratorList;
+typedef QVector<FileModelItem> FileList;
+typedef QVector<FunctionModelItem> FunctionList;
+typedef QVector<NamespaceModelItem> NamespaceList;
+typedef QVector<ScopeModelItem> ScopeList;
+typedef QVector<TemplateParameterModelItem> TemplateParameterList;
+typedef QVector<TypeDefModelItem> TypeDefList;
+typedef QVector<VariableModelItem> VariableList;
+typedef QVector<MemberModelItem> MemberList;
+
+#endif // CODEMODEL_FWD_H
diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
new file mode 100644
index 000000000..00e2384f0
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtdocparser.h"
+#include "abstractmetalang.h"
+#include "reporthandler.h"
+#include "typesystem.h"
+
+#include <QtXmlPatterns/QXmlQuery>
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QUrl>
+
+Documentation QtDocParser::retrieveModuleDocumentation()
+{
+ return retrieveModuleDocumentation(packageName());
+}
+
+void QtDocParser::fillDocumentation(AbstractMetaClass* metaClass)
+{
+ if (!metaClass)
+ return;
+
+ QString scope = metaClass->name();
+ const AbstractMetaClass* context = metaClass->enclosingClass();
+ while(context) {
+ if (context->enclosingClass() == 0)
+ break;
+ context = context->enclosingClass();
+ }
+
+ QString filename = metaClass->qualifiedCppName().toLower();
+ filename.replace(QLatin1String("::"), QLatin1String("-"));
+ QString sourceFile = documentationDataDirectory() + QLatin1Char('/')
+ + filename + QLatin1String(".xml");
+ if (metaClass->enclosingClass())
+ sourceFile.replace(QLatin1String("::"), QLatin1String("-"));
+
+ if (!QFile::exists(sourceFile)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't find qdoc3 file for class " << metaClass->name() << ", tried: "
+ << QDir::toNativeSeparators(sourceFile);
+ return;
+ }
+
+ QXmlQuery xquery;
+ xquery.setFocus(QUrl(sourceFile));
+
+ QString className = metaClass->name();
+
+ // Class/Namespace documentation
+ QString type = metaClass->isNamespace() ? QLatin1String("namespace") : QLatin1String("class");
+ QString query = QLatin1String("/WebXML/document/") + type + QLatin1String("[@name=\"")
+ + className + QLatin1String("\"]/description");
+
+ DocModificationList signedModifs, classModifs;
+ const DocModificationList &mods = metaClass->typeEntry()->docModifications();
+ for (const DocModification &docModif : mods) {
+ if (docModif.signature().isEmpty())
+ classModifs.append(docModif);
+ else
+ signedModifs.append(docModif);
+ }
+
+ Documentation doc(getDocumentation(xquery, query, classModifs));
+ metaClass->setDocumentation(doc);
+
+
+ //Functions Documentation
+ const AbstractMetaFunctionList &funcs = metaClass->functionsInTargetLang();
+ for (AbstractMetaFunction *func : funcs) {
+ if (!func || func->isPrivate())
+ continue;
+
+ QString query = QLatin1String("/WebXML/document/") + type
+ + QLatin1String("[@name=\"") + className + QLatin1String("\"]");
+ // properties
+ if (func->isPropertyReader() || func->isPropertyWriter() || func->isPropertyResetter()) {
+ query += QLatin1String("/property[@name=\"") + func->propertySpec()->name()
+ + QLatin1String("\"]");
+ } else { // normal methods
+ QString isConst = func->isConstant() ? QLatin1String("true") : QLatin1String("false");
+ query += QLatin1String("/function[@name=\"") + func->originalName()
+ + QLatin1String("\" and count(parameter)=")
+ + QString::number(func->arguments().count())
+ + QLatin1String(" and @const=\"") + isConst + QLatin1String("\"]");
+
+ const AbstractMetaArgumentList &arguments = func->arguments();
+ for (int i = 0, size = arguments.size(); i < size; ++i) {
+ const AbstractMetaArgument *arg = arguments.at(i);
+ QString type = arg->type()->name();
+
+ if (arg->type()->isConstant())
+ type.prepend(QLatin1String("const "));
+
+ if (arg->type()->referenceType() == LValueReference) {
+ type += QLatin1String(" &");
+ } else if (arg->type()->referenceType() == RValueReference) {
+ type += QLatin1String(" &&");
+ } else if (arg->type()->indirections()) {
+ type += QLatin1Char(' ');
+ for (int j = 0, max = arg->type()->indirections(); j < max; ++j)
+ type += QLatin1Char('*');
+ }
+ query += QLatin1String("/parameter[") + QString::number(i + 1)
+ + QLatin1String("][@left=\"") + type + QLatin1String("\"]/..");
+ }
+ }
+ query += QLatin1String("/description");
+ DocModificationList funcModifs;
+ for (const DocModification &funcModif : qAsConst(signedModifs)) {
+ if (funcModif.signature() == func->minimalSignature())
+ funcModifs.append(funcModif);
+ }
+ doc.setValue(getDocumentation(xquery, query, funcModifs));
+ func->setDocumentation(doc);
+ }
+#if 0
+ // Fields
+ const AbstractMetaFieldList &fields = metaClass->fields();
+ for (AbstractMetaField *field : fields) {
+ if (field->isPrivate())
+ return;
+
+ QString query = "/doxygen/compounddef/sectiondef/memberdef/name[text()=\"" + field->name() + "\"]/..";
+ Documentation doc = getDocumentation(DocModificationList(), xquery, query);
+ field->setDocumentation(doc);
+ }
+#endif
+ // Enums
+ const AbstractMetaEnumList &enums = metaClass->enums();
+ for (AbstractMetaEnum *meta_enum : enums) {
+ QString query = QLatin1String("/WebXML/document/") + type
+ + QLatin1String("[@name=\"")
+ + className + QLatin1String("\"]/enum[@name=\"")
+ + meta_enum->name() + QLatin1String("\"]/description");
+ doc.setValue(getDocumentation(xquery, query, DocModificationList()));
+ meta_enum->setDocumentation(doc);
+ }
+}
+
+Documentation QtDocParser::retrieveModuleDocumentation(const QString& name)
+{
+ // TODO: This method of acquiring the module name supposes that the target language uses
+ // dots as module separators in package names. Improve this.
+ QString moduleName = name;
+ moduleName.remove(0, name.lastIndexOf(QLatin1Char('.')) + 1);
+ QString sourceFile = documentationDataDirectory() + QLatin1Char('/')
+ + moduleName.toLower() + QLatin1String(".xml");
+
+ if (!QFile::exists(sourceFile)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't find qdoc3 file for module " << name << ", tried: "
+ << QDir::toNativeSeparators(sourceFile);
+ return Documentation();
+ }
+
+ QXmlQuery xquery;
+ xquery.setFocus(QUrl(sourceFile));
+
+ // Module documentation
+ QString query = QLatin1String("/WebXML/document/page[@name=\"") + moduleName + QLatin1String("\"]/description");
+ return Documentation(getDocumentation(xquery, query, DocModificationList()));
+}
diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.h b/sources/shiboken2/ApiExtractor/qtdocparser.h
new file mode 100644
index 000000000..f6bd479cd
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/qtdocparser.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTDOCPARSER_H
+#define QTDOCPARSER_H
+
+#include "docparser.h"
+
+class QtDocParser : public DocParser
+{
+public:
+ QtDocParser() {}
+ void fillDocumentation(AbstractMetaClass* metaClass) override;
+ Documentation retrieveModuleDocumentation() override;
+ Documentation retrieveModuleDocumentation(const QString& name) override;
+};
+
+#endif // QTDOCPARSER_H
+
diff --git a/sources/shiboken2/ApiExtractor/reporthandler.cpp b/sources/shiboken2/ApiExtractor/reporthandler.cpp
new file mode 100644
index 000000000..8abea42c6
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/reporthandler.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "reporthandler.h"
+#include "typesystem.h"
+#include "typedatabase.h"
+#include <QtCore/QSet>
+#include <cstring>
+#include <cstdarg>
+#include <cstdio>
+
+#if _WINDOWS || NOCOLOR
+ #define COLOR_END ""
+ #define COLOR_WHITE ""
+ #define COLOR_YELLOW ""
+ #define COLOR_GREEN ""
+#else
+ #define COLOR_END "\033[0m"
+ #define COLOR_WHITE "\033[1;37m"
+ #define COLOR_YELLOW "\033[1;33m"
+ #define COLOR_GREEN "\033[0;32m"
+#endif
+
+static bool m_silent = false;
+static int m_warningCount = 0;
+static int m_suppressedCount = 0;
+static ReportHandler::DebugLevel m_debugLevel = ReportHandler::NoDebug;
+static QSet<QString> m_reportedWarnings;
+static QString m_progressBuffer;
+static int m_step_size = 0;
+static int m_step = -1;
+static int m_step_warning = 0;
+
+Q_LOGGING_CATEGORY(lcShiboken, "qt.shiboken")
+
+static void printProgress()
+{
+ std::printf("%s", m_progressBuffer.toUtf8().data());
+ std::fflush(stdout);
+ m_progressBuffer.clear();
+}
+
+void ReportHandler::install()
+{
+ qInstallMessageHandler(ReportHandler::messageOutput);
+}
+
+ReportHandler::DebugLevel ReportHandler::debugLevel()
+{
+ return m_debugLevel;
+}
+
+void ReportHandler::setDebugLevel(ReportHandler::DebugLevel level)
+{
+ m_debugLevel = level;
+}
+
+int ReportHandler::suppressedCount()
+{
+ return m_suppressedCount;
+}
+
+int ReportHandler::warningCount()
+{
+ return m_warningCount;
+}
+
+void ReportHandler::setProgressReference(int max)
+{
+ m_step_size = max;
+ m_step = -1;
+}
+
+bool ReportHandler::isSilent()
+{
+ return m_silent;
+}
+
+void ReportHandler::setSilent(bool silent)
+{
+ m_silent = silent;
+}
+
+void ReportHandler::messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &text)
+{
+ if (type == QtWarningMsg) {
+ if (m_silent || m_reportedWarnings.contains(text))
+ return;
+ const TypeDatabase *db = TypeDatabase::instance();
+ if (db && db->isSuppressedWarning(text)) {
+ ++m_suppressedCount;
+ return;
+ }
+ ++m_warningCount;
+ ++m_step_warning;
+ m_reportedWarnings.insert(text);
+ }
+ fprintf(stderr, "%s\n", qPrintable(qFormatLogMessage(type, context, text)));
+}
+
+void ReportHandler::progress(const QString& str, ...)
+{
+ if (m_silent)
+ return;
+
+ if (m_step == -1) {
+ QTextStream buf(&m_progressBuffer);
+ buf.setFieldWidth(45);
+ buf.setFieldAlignment(QTextStream::AlignLeft);
+ buf << str;
+ printProgress();
+ m_step = 0;
+ }
+ m_step++;
+ if (m_step >= m_step_size) {
+ if (m_step_warning == 0) {
+ m_progressBuffer = QLatin1String("[" COLOR_GREEN "OK" COLOR_END "]\n");
+ } else {
+ m_progressBuffer = QLatin1String("[" COLOR_YELLOW "WARNING" COLOR_END "]\n");
+ }
+ printProgress();
+ m_step_warning = 0;
+ }
+}
diff --git a/sources/shiboken2/ApiExtractor/reporthandler.h b/sources/shiboken2/ApiExtractor/reporthandler.h
new file mode 100644
index 000000000..6896d6e86
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/reporthandler.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef REPORTHANDLER_H
+#define REPORTHANDLER_H
+
+#include <QLoggingCategory>
+#include <QString>
+
+Q_DECLARE_LOGGING_CATEGORY(lcShiboken)
+
+class ReportHandler
+{
+public:
+ enum DebugLevel { NoDebug, SparseDebug, MediumDebug, FullDebug };
+
+ static void install();
+
+ static DebugLevel debugLevel();
+ static void setDebugLevel(DebugLevel level);
+
+ static int warningCount();
+
+ static int suppressedCount();
+
+ template <typename T>
+ static void setProgressReference(T collection)
+ {
+ setProgressReference(collection.count());
+ }
+
+ static void setProgressReference(int max);
+
+ static void progress(const QString &str, ...);
+
+ static bool isDebug(DebugLevel level)
+ { return debugLevel() >= level; }
+
+ static bool isSilent();
+ static void setSilent(bool silent);
+
+private:
+ static void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
+};
+
+#endif // REPORTHANDLER_H
diff --git a/sources/shiboken2/ApiExtractor/symbols.filter b/sources/shiboken2/ApiExtractor/symbols.filter
new file mode 100644
index 000000000..af6c744dd
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/symbols.filter
@@ -0,0 +1,7 @@
+{
+local:
+_ZSt*;
+_ZNSt*;
+_ZNSs*;
+_ZNKSt*;
+};
diff --git a/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt
new file mode 100644
index 000000000..860a37d9d
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt
@@ -0,0 +1,74 @@
+find_package(Qt5Core)
+find_package(Qt5Gui)
+find_package(Qt5Test)
+find_package(Qt5Xml)
+find_package(Qt5XmlPatterns)
+
+macro(declare_test testname)
+ # gone: qt4_automoc("${testname}.cpp")
+ if (EXISTS "${testname}.h")
+ add_executable(${testname} "${testname}.h ${testname}.cpp")
+ else ()
+ add_executable(${testname} "${testname}.cpp")
+ endif ()
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${apiextractor_SOURCE_DIR}
+ ${Qt5Test_INCLUDE_DIRS}
+ )
+ link_directories(${APIEXTRACTOR_EXTRA_LINK_DIRECTORIES})
+ target_link_libraries(${testname}
+ ${Qt5XmlPatterns_LIBRARIES}
+ ${Qt5Test_LIBRARIES}
+ ${Qt5Core_LIBRARIES}
+ ${Qt5Gui_LIBRARIES}
+ apiextractor)
+ add_test(${testname} ${testname})
+ if (INSTALL_TESTS)
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${testname}
+ DESTINATION share/apiextractor${apiextractor_SUFFIX}/tests)
+ endif()
+endmacro(declare_test testname)
+
+declare_test(testabstractmetaclass)
+declare_test(testabstractmetatype)
+declare_test(testaddfunction)
+declare_test(testarrayargument)
+declare_test(testcodeinjection)
+configure_file("${CMAKE_CURRENT_SOURCE_DIR}/utf8code.txt"
+ "${CMAKE_CURRENT_BINARY_DIR}/utf8code.txt" COPYONLY)
+declare_test(testcontainer)
+declare_test(testconversionoperator)
+declare_test(testconversionruletag)
+declare_test(testctorinformation)
+declare_test(testdroptypeentries)
+declare_test(testdtorinformation)
+declare_test(testenum)
+declare_test(testextrainclude)
+declare_test(testfunctiontag)
+declare_test(testimplicitconversions)
+declare_test(testinserttemplate)
+declare_test(testmodifyfunction)
+declare_test(testmultipleinheritance)
+declare_test(testnamespace)
+declare_test(testnestedtypes)
+declare_test(testnumericaltypedef)
+declare_test(testprimitivetypetag)
+declare_test(testrefcounttag)
+declare_test(testreferencetopointer)
+declare_test(testremovefield)
+declare_test(testremoveimplconv)
+declare_test(testremoveoperatormethod)
+declare_test(testresolvetype)
+declare_test(testreverseoperators)
+declare_test(testtemplates)
+declare_test(testtoposort)
+declare_test(testvaluetypedefaultctortag)
+declare_test(testvoidarg)
+declare_test(testtyperevision)
+if (NOT DISABLE_DOCSTRINGS)
+ declare_test(testmodifydocumentation)
+ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/a.xml"
+ "${CMAKE_CURRENT_BINARY_DIR}/a.xml" COPYONLY)
+endif()
+
diff --git a/sources/shiboken2/ApiExtractor/tests/a.xml b/sources/shiboken2/ApiExtractor/tests/a.xml
new file mode 100644
index 000000000..1c6d62a17
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/a.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" ?>
+
+<WebXML>
+ <document>
+ <class name="A">
+ <description>oi
+ <para>Paragraph number 1</para>
+ <para>Paragraph number 2</para>
+ <para>Paragraph number 3</para>
+ </description>
+ </class>
+ </document>
+</WebXML>
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp
new file mode 100644
index 000000000..423b8d9ff
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.cpp
@@ -0,0 +1,527 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testabstractmetaclass.h"
+#include "abstractmetabuilder.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestAbstractMetaClass::testClassName()
+{
+ const char* cppCode ="class ClassName {};";
+ const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"ClassName\"/></typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+ QCOMPARE(classes[0]->name(), QLatin1String("ClassName"));
+}
+
+void TestAbstractMetaClass::testClassNameUnderNamespace()
+{
+ const char* cppCode ="namespace Namespace { class ClassName {}; }\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <namespace-type name=\"Namespace\"/>\n\
+ <value-type name=\"Namespace::ClassName\"/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2); // 1 namespace + 1 class
+ if (classes.first()->name() != QLatin1String("ClassName"))
+ qSwap(classes[0], classes[1]);
+
+ QCOMPARE(classes[0]->name(), QLatin1String("ClassName"));
+ QCOMPARE(classes[0]->qualifiedCppName(), QLatin1String("Namespace::ClassName"));
+ QCOMPARE(classes[1]->name(), QLatin1String("Namespace"));
+ QVERIFY(classes[1]->isNamespace());
+
+ // Check ctors info
+ QVERIFY(classes[0]->hasConstructors());
+ QCOMPARE(classes[0]->functions().size(), 2); // default ctor + copy ctor
+
+ AbstractMetaFunctionList ctors = classes[0]->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.first()->minimalSignature() != QLatin1String("ClassName()"))
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("ClassName()"));
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("ClassName(Namespace::ClassName)"));
+
+ QVERIFY(!classes[0]->hasPrivateDestructor());
+ QVERIFY(classes[0]->hasCloneOperator()); // implicit default copy ctor
+ QVERIFY(!classes[0]->hasHashFunction());
+
+ // This method is buggy and nobody wants to fix it or needs it fixed :-/
+ // QVERIFY(classes[0]->hasNonPrivateConstructor());
+}
+
+void TestAbstractMetaClass::testVirtualMethods()
+{
+ const char* cppCode ="\
+ class A {\n\
+ public:\n\
+ virtual int pureVirtual() const = 0;\n\
+ };\n\
+ class B : public A {};\n\
+ class C : public B {\n\
+ public:\n\
+ int pureVirtual() const { return 0; }\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ <object-type name='C'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 3);
+ AbstractMetaClass* a = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ AbstractMetaClass* b = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ AbstractMetaClass* c = AbstractMetaClass::findClass(classes, QLatin1String("C"));
+
+ AbstractMetaClass* no_class = 0;
+
+ QCOMPARE(a->baseClass(), no_class);
+ QCOMPARE(b->baseClass(), a);
+ QCOMPARE(c->baseClass(), b);
+
+ QCOMPARE(a->functions().size(), 2); // default ctor + the pure virtual method
+ QCOMPARE(b->functions().size(), 2);
+ QCOMPARE(c->functions().size(), 2);
+
+ // implementing class, ownclass, declaringclass
+ AbstractMetaFunction* ctorA = a->queryFunctions(AbstractMetaClass::Constructors).first();
+ AbstractMetaFunction* ctorB = b->queryFunctions(AbstractMetaClass::Constructors).first();
+ AbstractMetaFunction* ctorC = c->queryFunctions(AbstractMetaClass::Constructors).first();
+ QVERIFY(ctorA->isConstructor());
+ QVERIFY(!ctorA->isVirtual());
+ QVERIFY(ctorB->isConstructor());
+ QVERIFY(!ctorB->isVirtual());
+ QVERIFY(ctorC->isConstructor());
+ QVERIFY(!ctorC->isVirtual());
+ QCOMPARE(ctorA->implementingClass(), a);
+ QCOMPARE(ctorA->ownerClass(), a);
+ QCOMPARE(ctorA->declaringClass(), a);
+
+ QCOMPARE(a->virtualFunctions().size(), 1); // Add a pureVirtualMethods method !?
+ QCOMPARE(b->virtualFunctions().size(), 1);
+ QCOMPARE(c->virtualFunctions().size(), 1);
+
+ AbstractMetaFunction* funcA = a->virtualFunctions().first();
+ AbstractMetaFunction* funcB = b->virtualFunctions().first();
+ AbstractMetaFunction* funcC = c->virtualFunctions().first();
+
+ QCOMPARE(funcA->ownerClass(), a);
+ QCOMPARE(funcB->ownerClass(), b);
+ QCOMPARE(funcC->ownerClass(), c);
+
+ QCOMPARE(funcA->declaringClass(), a);
+ QCOMPARE(funcB->declaringClass(), a);
+ QCOMPARE(funcC->declaringClass(), a);
+
+ // The next two tests could return null, because it makes more sense.
+ // But we have too many code written relying on this behaviour where
+ // implementingClass is equals to declaringClass on pure virtual functions
+ QCOMPARE(funcA->implementingClass(), a);
+ QCOMPARE(funcB->implementingClass(), a);
+ QCOMPARE(funcC->implementingClass(), c);
+}
+
+void TestAbstractMetaClass::testDefaultValues()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ class B {};\n\
+ void method(B b = B());\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ <value-type name='A::B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QCOMPARE(classA->queryFunctionsByName(QLatin1String("method")).count(), 1);
+ AbstractMetaFunction* method = classA->queryFunctionsByName(QLatin1String("method")).first();
+ AbstractMetaArgument* arg = method->arguments().first();
+ QCOMPARE(arg->defaultValueExpression(), arg->originalDefaultValueExpression());
+}
+
+void TestAbstractMetaClass::testModifiedDefaultValues()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ class B {};\n\
+ void method(B b = B());\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <modify-function signature='method(A::B)'>\n\
+ <modify-argument index='1'>\n\
+ <replace-default-expression with='Hello'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </value-type>\n\
+ <value-type name='A::B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QCOMPARE(classA->queryFunctionsByName(QLatin1String("method")).count(), 1);
+ AbstractMetaFunction* method = classA->queryFunctionsByName(QLatin1String("method")).first();
+ AbstractMetaArgument* arg = method->arguments().first();
+ QCOMPARE(arg->defaultValueExpression(), QLatin1String("Hello"));
+ QCOMPARE(arg->originalDefaultValueExpression(), QLatin1String("A::B()"));
+}
+
+void TestAbstractMetaClass::testInnerClassOfAPolymorphicOne()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ class B {};\n\
+ virtual void method();\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <value-type name='A::B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QVERIFY(classA->isPolymorphic());
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("A::B"));
+ QVERIFY(classB);
+ QVERIFY(!classB->isPolymorphic());
+}
+
+void TestAbstractMetaClass::testForwardDeclaredInnerClass()
+{
+ const char cppCode[] ="\
+ class A {\n\
+ class B;\n\
+ };\n\
+ class A::B {\n\
+ public:\n\
+ void foo();\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ <value-type name='A::B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("A::B"));
+ QVERIFY(classB);
+ const AbstractMetaFunction *fooF = classB->findFunction(QLatin1String("foo"));
+ QVERIFY(fooF);
+}
+
+void TestAbstractMetaClass::testSpecialFunctions()
+{
+ const char cppCode[] ="\
+ struct A {\n\
+ A();\n\
+ A(const A&);\n\
+ A &operator=(const A&);\n\
+ };\n\
+ struct B {\n\
+ B();\n\
+ B(const B &);\n\
+ B &operator=(B);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 2);
+ QCOMPARE(ctors.first()->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction);
+ AbstractMetaFunctionList assigmentOps = classA->queryFunctionsByName(QLatin1String("operator="));
+ QCOMPARE(assigmentOps.size(), 1);
+ QCOMPARE(assigmentOps.first()->functionType(), AbstractMetaFunction::AssignmentOperatorFunction);
+
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+ ctors = classB->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 2);
+ QCOMPARE(ctors.first()->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction);
+ assigmentOps = classA->queryFunctionsByName(QLatin1String("operator="));
+ QCOMPARE(assigmentOps.size(), 1);
+ QCOMPARE(assigmentOps.first()->functionType(), AbstractMetaFunction::AssignmentOperatorFunction);
+}
+
+void TestAbstractMetaClass::testClassDefaultConstructors()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ \n\
+ struct B {\n\
+ B();\n\
+ private: \n\
+ B(const B&);\n\
+ };\n\
+ \n\
+ struct C {\n\
+ C(const C&);\n\
+ };\n\
+ \n\
+ struct D {\n\
+ private: \n\
+ D(const D&);\n\
+ };\n\
+ \n\
+ struct E {\n\
+ private: \n\
+ ~E();\n\
+ };\n\
+ \n\
+ struct F {\n\
+ F(int, int);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ <object-type name='D'/>\n\
+ <object-type name='E'/>\n\
+ <value-type name='F'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 6);
+
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 2);
+
+ AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.first()->minimalSignature() != QLatin1String("A()"))
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("A()"));
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("A(A)"));
+
+ AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+ QCOMPARE(classB->functions().size(), 2);
+ QCOMPARE(classB->functions().first()->minimalSignature(), QLatin1String("B()"));
+
+ AbstractMetaClass* classC = AbstractMetaClass::findClass(classes, QLatin1String("C"));
+ QVERIFY(classC);
+ QCOMPARE(classC->functions().size(), 1);
+ QCOMPARE(classC->functions().first()->minimalSignature(), QLatin1String("C(C)"));
+
+ AbstractMetaClass* classD = AbstractMetaClass::findClass(classes, QLatin1String("D"));
+ QVERIFY(classD);
+ QCOMPARE(classD->functions().size(), 1);
+ QCOMPARE(classD->functions().first()->minimalSignature(), QLatin1String("D(D)"));
+ QVERIFY(classD->functions().first()->isPrivate());
+
+ AbstractMetaClass* classE = AbstractMetaClass::findClass(classes, QLatin1String("E"));
+ QVERIFY(classE);
+ QVERIFY(classE->hasPrivateDestructor());
+ QCOMPARE(classE->functions().size(), 0);
+
+ AbstractMetaClass* classF = AbstractMetaClass::findClass(classes, QLatin1String("F"));
+ QVERIFY(classF);
+
+ ctors = classF->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.first()->minimalSignature() != QLatin1String("F(int,int)"))
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 2);
+ QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("F(int,int)"));
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("F(F)"));
+}
+
+void TestAbstractMetaClass::testClassInheritedDefaultConstructors()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ A();\n\
+ private: \n\
+ A(const A&);\n\
+ };\n\
+ struct B : public A {};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+
+ AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.first()->minimalSignature() != QLatin1String("A()"))
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), QLatin1String("A()"));
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), QLatin1String("A(A)"));
+ QVERIFY(ctors[1]->isPrivate());
+
+ AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+
+ ctors = classB->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.first()->arguments().size(), 0);
+ QCOMPARE(ctors.first()->minimalSignature(), QLatin1String("B()"));
+}
+
+void TestAbstractMetaClass::testAbstractClassDefaultConstructors()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ virtual void method() = 0;\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+
+ AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.first()->arguments().size(), 0);
+ QCOMPARE(ctors.first()->minimalSignature(), QLatin1String("A()"));
+}
+
+void TestAbstractMetaClass::testObjectTypesMustNotHaveCopyConstructors()
+{
+ const char* cppCode ="struct A {};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+
+ AbstractMetaFunctionList ctors = classA->queryFunctions(AbstractMetaClass::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.first()->arguments().size(), 0);
+ QCOMPARE(ctors.first()->minimalSignature(), QLatin1String("A()"));
+}
+
+void TestAbstractMetaClass::testIsPolymorphic()
+{
+ const char* cppCode = "\
+ class A\n\
+ {\n\
+ public:\n\
+ A();\n\
+ inline bool abc() const {}\n\
+ };\n\
+ \n\
+ class B : public A\n\
+ {\n\
+ public:\n\
+ B();\n\
+ inline bool abc() const {}\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='bool'/>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ AbstractMetaClass* b = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+
+ QVERIFY(!b->isPolymorphic());
+ AbstractMetaClass* a = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(!a->isPolymorphic());
+}
+
+QTEST_APPLESS_MAIN(TestAbstractMetaClass)
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.h b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.h
new file mode 100644
index 000000000..811bf5a10
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetaclass.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTABSTRACTMETACLASS_H
+#define TESTABSTRACTMETACLASS_H
+
+#include <QObject>
+
+class AbstractMetaBuilder;
+
+class TestAbstractMetaClass : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testClassName();
+ void testClassNameUnderNamespace();
+ void testVirtualMethods();
+ void testDefaultValues();
+ void testModifiedDefaultValues();
+ void testInnerClassOfAPolymorphicOne();
+ void testForwardDeclaredInnerClass();
+ void testSpecialFunctions();
+ void testClassDefaultConstructors();
+ void testClassInheritedDefaultConstructors();
+ void testAbstractClassDefaultConstructors();
+ void testObjectTypesMustNotHaveCopyConstructors();
+ void testIsPolymorphic();
+};
+
+#endif // TESTABSTRACTMETACLASS_H
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp
new file mode 100644
index 000000000..1d52c1e41
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testabstractmetatype.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestAbstractMetaType::testConstCharPtrType()
+{
+ const char* cppCode ="const char* justAtest();\n";
+ const char* xmlCode = "<typesystem package=\"Foo\">\n\
+ <primitive-type name='char'/>\n\
+ <function signature='justAtest()' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ AbstractMetaFunction* func = builder->globalFunctions().first();
+ AbstractMetaType* rtype = func->type();
+ // Test properties of const char*
+ QVERIFY(rtype);
+ QCOMPARE(rtype->package(), QLatin1String("Foo"));
+ QCOMPARE(rtype->name(), QLatin1String("char"));
+ QVERIFY(rtype->isConstant());
+ QVERIFY(!rtype->isArray());
+ QVERIFY(!rtype->isContainer());
+ QVERIFY(!rtype->isObject());
+ QVERIFY(!rtype->isPrimitive()); // const char* differs from char, so it's not considered a primitive type by apiextractor
+ QVERIFY(rtype->isNativePointer());
+ QVERIFY(!rtype->isQObject());
+ QCOMPARE(rtype->referenceType(), NoReference);
+ QVERIFY(!rtype->isValue());
+ QVERIFY(!rtype->isValuePointer());
+}
+
+void TestAbstractMetaType::testApiVersionSupported()
+{
+ const char* cppCode ="class foo {}; class foo2 {};\n\
+ void justAtest(); void justAtest3();\n";
+ const char* xmlCode = "<typesystem package='Foo'>\n\
+ <value-type name='foo' since='0.1'/>\n\
+ <value-type name='foo2' since='1.0'/>\n\
+ <value-type name='foo3' since='1.1'/>\n\
+ <function signature='justAtest()' since='0.1'/>\n\
+ <function signature='justAtest2()' since='1.1'/>\n\
+ <function signature='justAtest3()'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "1.0"));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+
+
+ AbstractMetaFunctionList functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 2);
+}
+
+
+void TestAbstractMetaType::testApiVersionNotSupported()
+{
+ const char* cppCode ="class object {};\n";
+ const char* xmlCode = "<typesystem package='Foo'>\n\
+ <value-type name='object' since='0.1'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+}
+
+void TestAbstractMetaType::testCharType()
+{
+ const char* cppCode ="char justAtest(); class A {};\n";
+ const char* xmlCode = "<typesystem package=\"Foo\">\n\
+ <primitive-type name='char'/>\n\
+ <value-type name='A'/>\n\
+ <function signature='justAtest()'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes.first()->package(), QLatin1String("Foo"));
+
+ AbstractMetaFunctionList functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ AbstractMetaFunction* func = functions.first();
+ AbstractMetaType* rtype = func->type();
+ // Test properties of const char*
+ QVERIFY(rtype);
+ QCOMPARE(rtype->package(), QLatin1String("Foo"));
+ QCOMPARE(rtype->name(), QLatin1String("char"));
+ QVERIFY(!rtype->isConstant());
+ QVERIFY(!rtype->isArray());
+ QVERIFY(!rtype->isContainer());
+ QVERIFY(!rtype->isObject());
+ QVERIFY(rtype->isPrimitive());
+ QVERIFY(!rtype->isNativePointer());
+ QVERIFY(!rtype->isQObject());
+ QCOMPARE(rtype->referenceType(), NoReference);
+ QVERIFY(!rtype->isValue());
+ QVERIFY(!rtype->isValuePointer());
+}
+
+void TestAbstractMetaType::testTypedef()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ void someMethod();\n\
+ };\n\
+ typedef A B;\n\
+ typedef B C;\n";
+ const char* xmlCode = "<typesystem package=\"Foo\">\n\
+ <value-type name='C' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const AbstractMetaClass *c = AbstractMetaClass::findClass(classes, QLatin1String("C"));
+ QVERIFY(c);
+ QVERIFY(c->isTypeDef());
+}
+
+void TestAbstractMetaType::testTypedefWithTemplates()
+{
+ const char* cppCode ="\
+ template<typename T>\n\
+ class A {};\n\
+ \n\
+ class B {};\n\
+ typedef A<B> C;\n\
+ \n\
+ void func(C c);\n";
+ const char* xmlCode = "<typesystem package=\"Foo\">\n\
+ <container-type name='A' type='list'/>\n\
+ <value-type name='B' />\n\
+ <function signature='func(A&lt;B&gt;)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ AbstractMetaFunctionList functions = builder->globalFunctions();
+ QCOMPARE(functions.count(), 1);
+ AbstractMetaFunction* function = functions.first();
+ AbstractMetaArgumentList args = function->arguments();
+ QCOMPARE(args.count(), 1);
+ AbstractMetaArgument* arg = args.first();
+ AbstractMetaType* metaType = arg->type();
+ QCOMPARE(metaType->cppSignature(), QLatin1String("A<B >"));
+}
+
+
+void TestAbstractMetaType::testObjectTypeUsedAsValue()
+{
+ const char* cppCode ="\
+ class A {\n\
+ void method(A);\n\
+ };\n";
+ const char* xmlCode = "<typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ AbstractMetaFunctionList overloads = classA->queryFunctionsByName(QLatin1String("method"));
+ QCOMPARE(overloads.count(), 1);
+ AbstractMetaFunction* method = overloads.first();
+ QVERIFY(method);
+ AbstractMetaArgumentList args = method->arguments();
+ QCOMPARE(args.count(), 1);
+ AbstractMetaArgument* arg = args.first();
+ AbstractMetaType* metaType = arg->type();
+ QCOMPARE(metaType->cppSignature(), QLatin1String("A"));
+ QVERIFY(metaType->isValue());
+ QVERIFY(metaType->typeEntry()->isObject());
+}
+
+QTEST_APPLESS_MAIN(TestAbstractMetaType)
diff --git a/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h
new file mode 100644
index 000000000..a806d36e3
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testabstractmetatype.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTABSTRACTMETATYPE_H
+#define TESTABSTRACTMETATYPE_H
+
+#include <QObject>
+
+class TestAbstractMetaType : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testConstCharPtrType();
+ void testCharType();
+ void testTypedef();
+ void testTypedefWithTemplates();
+ void testApiVersionSupported();
+ void testApiVersionNotSupported();
+ void testObjectTypeUsedAsValue();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
new file mode 100644
index 000000000..bcc5238bc
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.cpp
@@ -0,0 +1,453 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testaddfunction.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestAddFunction::testParsingFuncNameAndConstness()
+{
+ // generic test...
+ const char sig1[] = "func(type1, const type2, const type3* const)";
+ AddedFunction f1(QLatin1String(sig1), QLatin1String("void"), 0);
+ QCOMPARE(f1.name(), QLatin1String("func"));
+ QCOMPARE(f1.arguments().count(), 3);
+ AddedFunction::TypeInfo retval = f1.returnType();
+ QCOMPARE(retval.name, QLatin1String("void"));
+ QCOMPARE(retval.indirections, 0);
+ QCOMPARE(retval.isConstant, false);
+ QCOMPARE(retval.isReference, false);
+
+ // test with a ugly template as argument and other ugly stuff
+ const char sig2[] = " _fu__nc_ ( type1, const type2, const Abc<int& , C<char*> * > * *, const type3* const ) const ";
+ AddedFunction f2(QLatin1String(sig2), QLatin1String("const Abc<int& , C<char*> * > * *"), 0);
+ QCOMPARE(f2.name(), QLatin1String("_fu__nc_"));
+ QVector< AddedFunction::TypeInfo > args = f2.arguments();
+ QCOMPARE(args.count(), 4);
+ retval = f2.returnType();
+ QCOMPARE(retval.name, QLatin1String("Abc<int& , C<char*> * >"));
+ QCOMPARE(retval.indirections, 2);
+ QCOMPARE(retval.isConstant, true);
+ QCOMPARE(retval.isReference, false);
+ retval = args[2];
+ QCOMPARE(retval.name, QLatin1String("Abc<int& , C<char*> * >"));
+ QCOMPARE(retval.indirections, 2);
+ QCOMPARE(retval.isConstant, true);
+ QCOMPARE(retval.isReference, false);
+
+ // function with no args.
+ const char sig3[] = "func()";
+ AddedFunction f3(QLatin1String(sig3), QLatin1String("void"), 0);
+ QCOMPARE(f3.name(), QLatin1String("func"));
+ QCOMPARE(f3.arguments().count(), 0);
+}
+
+void TestAddFunction::testAddFunction()
+{
+ const char cppCode[] = "struct B {}; struct A { void a(int); };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='float'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='b(int, float = 4.6, const B&amp;)' return-type='int' access='protected'>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().count(), 4); // default ctor, default copy ctor, func a() and the added function
+
+ AbstractMetaFunction* addedFunc = classA->functions().last();
+ QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Protected);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QVERIFY(addedFunc->isUserAdded());
+ QCOMPARE(addedFunc->ownerClass(), classA);
+ QCOMPARE(addedFunc->implementingClass(), classA);
+ QCOMPARE(addedFunc->declaringClass(), classA);
+ QVERIFY(!addedFunc->isVirtual());
+ QVERIFY(!addedFunc->isSignal());
+ QVERIFY(!addedFunc->isSlot());
+ QVERIFY(!addedFunc->isStatic());
+
+ AbstractMetaType* returnType = addedFunc->type();
+ QCOMPARE(returnType->typeEntry(), typeDb->findPrimitiveType(QLatin1String("int")));
+ AbstractMetaArgumentList args = addedFunc->arguments();
+ QCOMPARE(args.count(), 3);
+ QCOMPARE(args[0]->type()->typeEntry(), returnType->typeEntry());
+ QCOMPARE(args[1]->defaultValueExpression(), QLatin1String("4.6"));
+ QCOMPARE(args[2]->type()->typeEntry(), typeDb->findType(QLatin1String("B")));
+}
+
+void TestAddFunction::testAddFunctionConstructor()
+{
+ const char cppCode[] = "struct A { A() {} };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='A(int)'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().count(), 3); // default and added ctors
+ AbstractMetaFunction* addedFunc = classA->functions().last();
+ QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(addedFunc->arguments().size(), 1);
+ QVERIFY(addedFunc->isUserAdded());
+ QVERIFY(!addedFunc->type());
+}
+
+void TestAddFunction::testAddFunctionTagDefaultValues()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func()'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().count(), 3); // default ctor, default copy ctor and the added function
+ AbstractMetaFunction* addedFunc = classA->functions().last();
+ QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QVERIFY(addedFunc->isUserAdded());
+ QVERIFY(!addedFunc->type());
+}
+
+void TestAddFunction::testAddFunctionCodeSnippets()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func()'>\n\
+ <inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ AbstractMetaFunction* addedFunc = classA->functions().last();
+ QVERIFY(addedFunc->hasInjectedCode());
+}
+
+void TestAddFunction::testAddFunctionWithoutParenteses()
+{
+ const char sig1[] = "func";
+ AddedFunction f1(QLatin1String(sig1), QLatin1String("void"), 0);
+
+ QCOMPARE(f1.name(), QLatin1String("func"));
+ QCOMPARE(f1.arguments().count(), 0);
+ QCOMPARE(f1.isConstant(), false);
+
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func'>\n\
+ <inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("func"));
+ QVERIFY(addedFunc);
+ QVERIFY(addedFunc->hasInjectedCode());
+ QCOMPARE(addedFunc->injectedCodeSnips(TypeSystem::CodeSnipPositionAny, TypeSystem::TargetLangCode).count(), 1);
+}
+
+void TestAddFunction::testAddFunctionWithDefaultArgs()
+{
+ const char sig1[] = "func";
+ AddedFunction f1(QLatin1String(sig1), QLatin1String("void"), 0);
+
+ QCOMPARE(f1.name(), QLatin1String("func"));
+ QCOMPARE(f1.arguments().count(), 0);
+ QCOMPARE(f1.isConstant(), false);
+
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int, int)'>\n\
+ <modify-argument index='2'>\n\
+ <replace-default-expression with='2'/>\n\
+ </modify-argument>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("func"));
+ QVERIFY(addedFunc);
+ AbstractMetaArgument *arg = addedFunc->arguments()[1];
+ QCOMPARE(arg->defaultValueExpression(), QLatin1String("2"));
+}
+
+void TestAddFunction::testAddFunctionAtModuleLevel()
+{
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <add-function signature='func(int, int)'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+
+ TypeDatabase* typeDb = TypeDatabase::instance();
+
+ AddedFunctionList addedFuncs = typeDb->findGlobalUserFunctions(QLatin1String("func"));
+
+ QCOMPARE(addedFuncs.size(), 1);
+
+ FunctionModificationList mods = typeDb->functionModifications(QLatin1String("func(int,int)"));
+
+ QCOMPARE(mods.size(), 1);
+ QVERIFY(mods.first().isCodeInjection());
+ CodeSnip snip = mods.first().snips.first();
+ QCOMPARE(snip.code(), QLatin1String("custom_code();"));
+}
+
+void TestAddFunction::testAddFunctionWithVarargs()
+{
+ const char sig1[] = "func(int,char,...)";
+ AddedFunction f1( QLatin1String(sig1), QLatin1String("void"), 0);
+
+ QCOMPARE(f1.name(), QLatin1String("func"));
+ QCOMPARE(f1.arguments().count(), 3);
+ QVERIFY(!f1.isConstant());
+
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='char'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int,char,...)'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("func"));
+ QVERIFY(addedFunc);
+ const AbstractMetaArgument* arg = addedFunc->arguments().last();
+ QVERIFY(arg->type()->isVarargs());
+ QVERIFY(arg->type()->typeEntry()->isVarargs());
+}
+
+void TestAddFunction::testAddStaticFunction()
+{
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("func"));
+ QVERIFY(addedFunc);
+ QVERIFY(addedFunc->isStatic());
+}
+
+void TestAddFunction::testAddGlobalFunction()
+{
+ const char cppCode[] = "struct A { };struct B {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <add-function signature='globalFunc(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='globalFunc2(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaFunctionList globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.count(), 2);
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(builder->classes(), QLatin1String("B"));
+ QVERIFY(classB);
+ QVERIFY(!classB->findFunction(QLatin1String("globalFunc")));
+ QVERIFY(!classB->findFunction(QLatin1String("globalFunc2")));
+ QVERIFY(!globalFuncs[0]->injectedCodeSnips().isEmpty());
+ QVERIFY(!globalFuncs[1]->injectedCodeSnips().isEmpty());
+}
+
+void TestAddFunction::testAddFunctionWithApiVersion()
+{
+ const char cppCode[] = "";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <add-function signature='globalFunc(int, int)' static='yes' since='1.3'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='globalFunc2(int, int)' static='yes' since='0.1'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QVERIFY(!builder.isNull());
+ AbstractMetaFunctionList globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.count(), 1);
+}
+
+void TestAddFunction::testModifyAddedFunction()
+{
+ const char cppCode[] = "class Foo { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Package'>\n\
+ <primitive-type name='float'/>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='Foo'>\n\
+ <add-function signature='method(float, int)'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ <modify-argument index='2'>\n\
+ <replace-default-expression with='0'/>\n\
+ <rename to='varName'/>\n\
+ </modify-argument>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClass* foo = AbstractMetaClass::findClass(classes, QLatin1String("Foo"));
+ const AbstractMetaFunction* method = foo->findFunction(QLatin1String("method"));
+ QCOMPARE(method->arguments().size(), 2);
+ AbstractMetaArgument* arg = method->arguments().at(1);
+ QCOMPARE(arg->defaultValueExpression(), QLatin1String("0"));
+ QCOMPARE(arg->name(), QLatin1String("varName"));
+ QCOMPARE(method->argumentName(2), QLatin1String("varName"));
+}
+
+void TestAddFunction::testAddFunctionOnTypedef()
+{
+ const char cppCode[] = "template<class T> class Foo { }; typedef Foo<int> FooInt;\n";
+ const char xmlCode[] = "\
+ <typesystem package='Package'>\n\
+ <custom-type name='PySequence'/>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='FooInt'>\n\
+ <add-function signature='FooInt(PySequence)'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='method()'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClass* foo = AbstractMetaClass::findClass(classes, QLatin1String("FooInt"));
+ QVERIFY(foo);
+ QVERIFY(foo->hasNonPrivateConstructor());
+ const AbstractMetaFunctionList &lst = foo->queryFunctions(AbstractMetaClass::Constructors);
+ for (const AbstractMetaFunction *f : lst)
+ QVERIFY(f->signature().startsWith(f->name()));
+ QCOMPARE(lst.size(), 2);
+ const AbstractMetaFunction* method = foo->findFunction(QLatin1String("method"));
+ QVERIFY(method);
+}
+
+void TestAddFunction::testAddFunctionWithTemplateArg()
+{
+ const char cppCode[] = "template<class T> class Foo { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Package'>\n\
+ <primitive-type name='int'/>\n\
+ <container-type name='Foo' type='list'/>\n\
+ <add-function signature='func(Foo&lt;int>)'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ AbstractMetaFunction* func = builder->globalFunctions().first();
+ AbstractMetaArgument* arg = func->arguments().first();
+ QCOMPARE(arg->type()->instantiations().count(), 1);
+}
+
+QTEST_APPLESS_MAIN(TestAddFunction)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testaddfunction.h b/sources/shiboken2/ApiExtractor/tests/testaddfunction.h
new file mode 100644
index 000000000..16a4ede09
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testaddfunction.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTADDFUNCTION_H
+#define TESTADDFUNCTION_H
+#include <QObject>
+
+class TestAddFunction : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testParsingFuncNameAndConstness();
+ void testAddFunction();
+ void testAddFunctionConstructor();
+ void testAddFunctionTagDefaultValues();
+ void testAddFunctionCodeSnippets();
+ void testAddFunctionWithoutParenteses();
+ void testAddFunctionWithDefaultArgs();
+ void testAddFunctionAtModuleLevel();
+ void testAddFunctionWithVarargs();
+ void testAddStaticFunction();
+ void testAddGlobalFunction();
+ void testAddFunctionWithApiVersion();
+ void testModifyAddedFunction();
+ void testAddFunctionOnTypedef();
+ void testAddFunctionWithTemplateArg();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp b/sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp
new file mode 100644
index 000000000..4d46d44bc
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testarrayargument.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByInteger()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ void method(double[3]);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='A'>\n\
+ <enum-type name='SomeEnum'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
+ QVERIFY(classA);
+
+ const AbstractMetaArgument* arg = classA->functions().last()->arguments().first();
+ QVERIFY(arg->type()->isArray());
+ QCOMPARE(arg->type()->arrayElementCount(), 3);
+ QCOMPARE(arg->type()->arrayElementType()->name(), QLatin1String("double"));
+}
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValue()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ void method(double[NValues]);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='A'>\n\
+ <enum-type name='SomeEnum'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
+ QVERIFY(classA);
+
+ AbstractMetaEnum* someEnum = classA->findEnum(QLatin1String("SomeEnum"));
+ QVERIFY(someEnum);
+ AbstractMetaEnumValue* nvalues = classA->findEnumValue(QLatin1String("NValues"), someEnum);
+ QVERIFY(nvalues);
+
+ const AbstractMetaArgument* arg = classA->functions().last()->arguments().first();
+ QVERIFY(arg->type()->isArray());
+ QCOMPARE(arg->type()->arrayElementCount(), nvalues->value());
+ QCOMPARE(arg->type()->arrayElementType()->name(), QLatin1String("double"));
+};
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum()
+{
+ const char* cppCode ="\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ struct A {\n\
+ void method(double[NValues]);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <enum-type name='SomeEnum'/>\n\
+ <object-type name='A'>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
+ QVERIFY(classA);
+
+ AbstractMetaEnum* someEnum = builder->globalEnums().first();
+ QVERIFY(someEnum);
+ AbstractMetaEnumValue* nvalues = 0;
+ const AbstractMetaEnumValueList &values = someEnum->values();
+ for (AbstractMetaEnumValue *enumValue : values) {
+ if (enumValue->name() == QLatin1String("NValues")) {
+ nvalues = enumValue;
+ break;
+ }
+ }
+ QVERIFY(nvalues);
+
+ const AbstractMetaArgument* arg = classA->functions().last()->arguments().first();
+ QVERIFY(arg->type()->isArray());
+ QCOMPARE(arg->type()->arrayElementCount(), nvalues->value());
+ QCOMPARE(arg->type()->arrayElementType()->name(), QLatin1String("double"));
+};
+
+QTEST_APPLESS_MAIN(TestArrayArgument)
diff --git a/sources/shiboken2/ApiExtractor/tests/testarrayargument.h b/sources/shiboken2/ApiExtractor/tests/testarrayargument.h
new file mode 100644
index 000000000..b50232ef4
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testarrayargument.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTARRAYARGUMENT_H
+#define TESTARRAYARGUMENT_H
+#include <QObject>
+
+class TestArrayArgument : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testArrayArgumentWithSizeDefinedByInteger();
+ void testArrayArgumentWithSizeDefinedByEnumValue();
+ void testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
new file mode 100644
index 000000000..ad245633e
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testcodeinjection.h"
+#include <QFileInfo>
+#include <QDir>
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestCodeInjections::testReadFileUtf8()
+{
+ const char* cppCode ="struct A {};\n";
+ int argc = 0;
+ char *argv[] = {NULL};
+ QCoreApplication app(argc, argv);
+ QString filePath = QDir::currentPath();
+ QString xmlCode = QLatin1String("\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <conversion-rule file='") + filePath + QLatin1String("/utf8code.txt'/>\n\
+ <inject-code class='target' file='") + filePath
+ + QLatin1String("/utf8code.txt'/>\n\
+ </value-type>\n\
+ <value-type name='A::B'/>\n\
+ </typesystem>\n");
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().constData()));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QCOMPARE(classA->typeEntry()->codeSnips().count(), 1);
+ QString code = classA->typeEntry()->codeSnips().first().code();
+ QString utf8Data = QString::fromUtf8("\xC3\xA1\xC3\xA9\xC3\xAD\xC3\xB3\xC3\xBA");
+ QVERIFY(code.indexOf(utf8Data) != -1);
+ code = classA->typeEntry()->conversionRule();
+ QVERIFY(code.indexOf(utf8Data) != -1);
+}
+
+void TestCodeInjections::testInjectWithValidApiVersion()
+{
+ const char* cppCode ="struct A {};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <inject-code class='target' since='1.0'>\n\
+ test Inject code\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "1.0"));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QCOMPARE(classA->typeEntry()->codeSnips().count(), 1);
+}
+
+void TestCodeInjections::testInjectWithInvalidApiVersion()
+{
+ const char* cppCode ="struct A {};\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <inject-code class='target' since='1.0'>\n\
+ test Inject code\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QCOMPARE(classA->typeEntry()->codeSnips().count(), 0);
+}
+
+
+
+QTEST_APPLESS_MAIN(TestCodeInjections)
diff --git a/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h
new file mode 100644
index 000000000..56c1c7cba
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testcodeinjection.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTCODEINJECTIONS_H
+#define TESTCODEINJECTIONS_H
+
+#include <QObject>
+
+class AbstractMetaBuilder;
+
+class TestCodeInjections : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testReadFileUtf8();
+ void testInjectWithValidApiVersion();
+ void testInjectWithInvalidApiVersion();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testcontainer.cpp b/sources/shiboken2/ApiExtractor/tests/testcontainer.cpp
new file mode 100644
index 000000000..1c79a5a7a
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testcontainer.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testcontainer.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestContainer::testContainerType()
+{
+ const char* cppCode ="\
+ namespace std {\n\
+ template<class T>\n\
+ class list {\n\
+ T get(int x) { return 0; }\n\
+ };\n\
+ }\n\
+ class A : public std::list<int> {\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='std' generate='no' />\n\
+ <container-type name='std::list' type='list' />\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ //search for class A
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QVERIFY(classA->typeEntry()->baseContainerType());
+ QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(classA->typeEntry()->baseContainerType())->type(), ContainerTypeEntry::ListContainer);
+}
+
+void TestContainer::testListOfValueType()
+{
+ const char* cppCode ="\
+ namespace std {\n\
+ template<class T>\n\
+ class list {\n\
+ T get(int x) { return 0; }\n\
+ };\n\
+ }\n\
+ class ValueType {};\n\
+ class A : public std::list<ValueType> {\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='std' generate='no'/>\n\
+ <container-type name='std::list' type='list'/>\n\
+ <value-type name='ValueType'/>\n\
+ <value-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 3);
+
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->templateBaseClassInstantiations().count(), 1);
+ const AbstractMetaType* templateInstanceType = classA->templateBaseClassInstantiations().first();
+ QVERIFY(templateInstanceType);
+
+ QCOMPARE(templateInstanceType->indirections(), 0);
+ QVERIFY(!templateInstanceType->typeEntry()->isObject());
+ QVERIFY(templateInstanceType->typeEntry()->isValue());
+ QCOMPARE(templateInstanceType->referenceType(), NoReference);
+ QVERIFY(!templateInstanceType->isObject());
+ QVERIFY(!templateInstanceType->isValuePointer());
+ QVERIFY(templateInstanceType->isValue());
+}
+
+QTEST_APPLESS_MAIN(TestContainer)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testcontainer.h b/sources/shiboken2/ApiExtractor/tests/testcontainer.h
new file mode 100644
index 000000000..f154ea212
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testcontainer.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTCONTAINER_H
+#define TESTCONTAINER_H
+#include <QObject>
+
+class TestContainer : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testContainerType();
+ void testListOfValueType();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testconversionoperator.cpp b/sources/shiboken2/ApiExtractor/tests/testconversionoperator.cpp
new file mode 100644
index 000000000..86f571328
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testconversionoperator.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testconversionoperator.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestConversionOperator::testConversionOperator()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n\
+ struct C {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C"));
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QVERIFY(classC);
+ QCOMPARE(classA->functions().count(), 2);
+ QCOMPARE(classB->functions().count(), 3);
+ QCOMPARE(classC->functions().count(), 3);
+ QCOMPARE(classA->externalConversionOperators().count(), 2);
+
+ AbstractMetaFunction* convOp = 0;
+ for (AbstractMetaFunction *func : classB->functions()) {
+ if (func->isConversionOperator()) {
+ convOp = func;
+ break;
+ }
+ }
+ QVERIFY(convOp);
+ QVERIFY(classA->externalConversionOperators().contains(convOp));
+}
+
+void TestConversionOperator::testConversionOperatorOfDiscardedClass()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->externalConversionOperators().count(), 0);
+}
+
+void TestConversionOperator::testRemovedConversionOperator()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ <value-type name='B'>\n\
+ <modify-function signature='operator A() const' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().count(), 2);
+ QCOMPARE(classB->functions().count(), 3);
+ QCOMPARE(classA->externalConversionOperators().count(), 0);
+ QCOMPARE(classA->implicitConversions().count(), 0);
+}
+
+void TestConversionOperator::testConversionOperatorReturningReference()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ operator A&() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().count(), 2);
+ QCOMPARE(classB->functions().count(), 3);
+ QCOMPARE(classA->externalConversionOperators().count(), 1);
+ QCOMPARE(classA->externalConversionOperators().first()->type()->cppSignature(), QLatin1String("A"));
+ QCOMPARE(classA->externalConversionOperators().first()->ownerClass()->name(), QLatin1String("B"));
+ QCOMPARE(classA->implicitConversions().count(), 1);
+ QCOMPARE(classA->implicitConversions().first()->type()->cppSignature(), QLatin1String("A"));
+ QCOMPARE(classA->implicitConversions().first()->ownerClass()->name(), QLatin1String("B"));
+}
+
+void TestConversionOperator::testConversionOperatorReturningConstReference()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ operator const A&() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().count(), 2);
+ QCOMPARE(classB->functions().count(), 3);
+ QCOMPARE(classA->externalConversionOperators().count(), 1);
+ QCOMPARE(classA->externalConversionOperators().first()->type()->cppSignature(), QLatin1String("A"));
+ QCOMPARE(classA->externalConversionOperators().first()->ownerClass()->name(), QLatin1String("B"));
+ QCOMPARE(classA->implicitConversions().count(), 1);
+ QCOMPARE(classA->implicitConversions().first()->type()->cppSignature(), QLatin1String("A"));
+ QCOMPARE(classA->implicitConversions().first()->ownerClass()->name(), QLatin1String("B"));
+}
+
+QTEST_APPLESS_MAIN(TestConversionOperator)
diff --git a/sources/shiboken2/ApiExtractor/tests/testconversionoperator.h b/sources/shiboken2/ApiExtractor/tests/testconversionoperator.h
new file mode 100644
index 000000000..f28747ab5
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testconversionoperator.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTCONVERSIONOPERATOR_H
+#define TESTCONVERSIONOPERATOR_H
+#include <QObject>
+
+class TestConversionOperator : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testConversionOperator();
+ void testConversionOperatorOfDiscardedClass();
+ void testRemovedConversionOperator();
+ void testConversionOperatorReturningReference();
+ void testConversionOperatorReturningConstReference();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testconversionruletag.cpp b/sources/shiboken2/ApiExtractor/tests/testconversionruletag.cpp
new file mode 100644
index 000000000..fb9290795
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testconversionruletag.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testconversionruletag.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+#include <QFile>
+#include <QTemporaryFile>
+
+void TestConversionRuleTag::testConversionRuleTagWithFile()
+{
+ // temp file used later
+ const char conversionData[] = "Hi! I'm a conversion rule.";
+ QTemporaryFile file;
+ file.open();
+ QCOMPARE(file.write(conversionData), qint64(sizeof(conversionData)-1));
+ file.close();
+
+ const char cppCode[] = "struct A {};\n";
+ QString xmlCode = QLatin1String("\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <conversion-rule file='") + file.fileName() + QLatin1String("'/>\n\
+ </value-type>\n\
+ </typesystem>\n");
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().data()));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const ComplexTypeEntry* typeEntry = classA->typeEntry();
+ QVERIFY(typeEntry->hasConversionRule());
+ QCOMPARE(typeEntry->conversionRule(), QLatin1String(conversionData));
+}
+
+void TestConversionRuleTag::testConversionRuleTagReplace()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ A();\n\
+ A(const char*, int);\n\
+ };\n\
+ struct B {\n\
+ A createA();\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='char'/>\n\
+ <primitive-type name='A'>\n\
+ <conversion-rule>\n\
+ <native-to-target>\n\
+ DoThis();\n\
+ return ConvertFromCppToPython(%IN);\n\
+ </native-to-target>\n\
+ <target-to-native>\n\
+ <add-conversion type='TargetNone' check='%IN == Target_None'>\n\
+ DoThat();\n\
+ DoSomething();\n\
+ %OUT = A();\n\
+ </add-conversion>\n\
+ <add-conversion type='B' check='CheckIfInputObjectIsB(%IN)'>\n\
+ %OUT = %IN.createA();\n\
+ </add-conversion>\n\
+ <add-conversion type='String' check='String_Check(%IN)'>\n\
+ %OUT = new A(String_AsString(%IN), String_GetSize(%IN));\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </primitive-type>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType(QLatin1String("A"));
+ QVERIFY(typeA);
+
+ CustomConversion* conversion = typeA->customConversion();
+ QVERIFY(conversion);
+
+ QCOMPARE(typeA, conversion->ownerType());
+ QCOMPARE(conversion->nativeToTargetConversion().simplified(),
+ QLatin1String("DoThis(); return ConvertFromCppToPython(%IN);"));
+
+ QVERIFY(conversion->replaceOriginalTargetToNativeConversions());
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 3);
+
+ CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().at(0);
+ QVERIFY(toNative);
+ QCOMPARE(toNative->sourceTypeName(), QLatin1String("TargetNone"));
+ QVERIFY(toNative->isCustomType());
+ QCOMPARE(toNative->sourceType(), (const TypeEntry*)0);
+ QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("%IN == Target_None"));
+ QCOMPARE(toNative->conversion().simplified(),
+ QLatin1String("DoThat(); DoSomething(); %OUT = A();"));
+
+ toNative = conversion->targetToNativeConversions().at(1);
+ QVERIFY(toNative);
+ QCOMPARE(toNative->sourceTypeName(), QLatin1String("B"));
+ QVERIFY(!toNative->isCustomType());
+ TypeEntry* typeB = typeDb->findType(QLatin1String("B"));
+ QVERIFY(typeB);
+ QCOMPARE(toNative->sourceType(), typeB);
+ QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("CheckIfInputObjectIsB(%IN)"));
+ QCOMPARE(toNative->conversion().trimmed(), QLatin1String("%OUT = %IN.createA();"));
+
+ toNative = conversion->targetToNativeConversions().at(2);
+ QVERIFY(toNative);
+ QCOMPARE(toNative->sourceTypeName(), QLatin1String("String"));
+ QVERIFY(toNative->isCustomType());
+ QCOMPARE(toNative->sourceType(), (const TypeEntry*)0);
+ QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("String_Check(%IN)"));
+ QCOMPARE(toNative->conversion().trimmed(), QLatin1String("%OUT = new A(String_AsString(%IN), String_GetSize(%IN));"));
+}
+
+void TestConversionRuleTag::testConversionRuleTagAdd()
+{
+ const char cppCode[] = "\
+ struct Date {\n\
+ Date();\n\
+ Date(int, int, int);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='Date'>\n\
+ <conversion-rule>\n\
+ <target-to-native replace='no'>\n\
+ <add-conversion type='TargetDate' check='TargetDate_Check(%IN)'>\n\
+if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n\
+%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("Date"));
+ QVERIFY(classA);
+
+ CustomConversion* conversion = classA->typeEntry()->customConversion();
+ QVERIFY(conversion);
+
+ QCOMPARE(conversion->nativeToTargetConversion(), QString());
+
+ QVERIFY(!conversion->replaceOriginalTargetToNativeConversions());
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 1);
+
+ CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().first();
+ QVERIFY(toNative);
+ QCOMPARE(toNative->sourceTypeName(), QLatin1String("TargetDate"));
+ QVERIFY(toNative->isCustomType());
+ QCOMPARE(toNative->sourceType(), (const TypeEntry*)0);
+ QCOMPARE(toNative->sourceTypeCheck(), QLatin1String("TargetDate_Check(%IN)"));
+ QCOMPARE(toNative->conversion().trimmed(),
+ QLatin1String("if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));"));
+}
+
+void TestConversionRuleTag::testConversionRuleTagWithInsertTemplate()
+{
+ const char cppCode[] = "struct A {};";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <!-- single line -->\n\
+ <template name='native_to_target'>return ConvertFromCppToPython(%IN);</template>\n\
+ <!-- multi-line -->\n\
+ <template name='target_to_native'>\n\
+%OUT = %IN.createA();\n\
+ </template>\n\
+ <primitive-type name='A'>\n\
+ <conversion-rule>\n\
+ <native-to-target>\n\
+ <insert-template name='native_to_target'/>\n\
+ </native-to-target>\n\
+ <target-to-native>\n\
+ <add-conversion type='TargetType'>\n\
+ <insert-template name='target_to_native'/>\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </primitive-type>\n\
+ </typesystem>\n";
+
+ const char nativeToTargetExpected[] =
+ "// TEMPLATE - native_to_target - START\n"
+ "return ConvertFromCppToPython(%IN);\n"
+ "// TEMPLATE - native_to_target - END";
+
+ const char targetToNativeExpected[] =
+ "// TEMPLATE - target_to_native - START\n"
+ "%OUT = %IN.createA();\n"
+ "// TEMPLATE - target_to_native - END";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ TypeDatabase* typeDb = TypeDatabase::instance();
+ PrimitiveTypeEntry* typeA = typeDb->findPrimitiveType(QLatin1String("A"));
+ QVERIFY(typeA);
+
+ CustomConversion* conversion = typeA->customConversion();
+ QVERIFY(conversion);
+
+ QCOMPARE(typeA, conversion->ownerType());
+ QCOMPARE(conversion->nativeToTargetConversion().trimmed(),
+ QLatin1String(nativeToTargetExpected));
+
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 1);
+
+ CustomConversion::TargetToNativeConversion* toNative = conversion->targetToNativeConversions().first();
+ QVERIFY(toNative);
+ QCOMPARE(toNative->conversion().trimmed(),
+ QLatin1String(targetToNativeExpected));
+}
+
+QTEST_APPLESS_MAIN(TestConversionRuleTag)
diff --git a/sources/shiboken2/ApiExtractor/tests/testconversionruletag.h b/sources/shiboken2/ApiExtractor/tests/testconversionruletag.h
new file mode 100644
index 000000000..c02a9708b
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testconversionruletag.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTCONVERSIONRULE_H
+#define TESTCONVERSIONRULE_H
+#include <QObject>
+
+class TestConversionRuleTag : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testConversionRuleTagWithFile();
+ void testConversionRuleTagReplace();
+ void testConversionRuleTagAdd();
+ void testConversionRuleTagWithInsertTemplate();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testctorinformation.cpp b/sources/shiboken2/ApiExtractor/tests/testctorinformation.cpp
new file mode 100644
index 000000000..a4b4c2388
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testctorinformation.cpp
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testctorinformation.h"
+#include "abstractmetabuilder.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestCtorInformation::testCtorIsPrivate()
+{
+ const char* cppCode = "class Control { public: Control() {} };\n\
+ class Subject { private: Subject() {} };\n\
+ class CtorLess { };\n";
+ const char* xmlCode = "<typesystem package='Foo'>\n\
+ <value-type name='Control'/>\n\
+ <object-type name='Subject'/>\n\
+ <value-type name='CtorLess'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 3);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasNonPrivateConstructor(), true);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasNonPrivateConstructor(), false);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("CtorLess"))->hasNonPrivateConstructor(), true);
+}
+
+void TestCtorInformation::testHasNonPrivateCtor()
+{
+ const char* cppCode = "template<typename T>\n\
+ struct Base { Base(double) {} };\n\
+ typedef Base<int> Derived;\n";
+ const char* xmlCode = "<typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='Base' generate='no'/>\n\
+ <object-type name='Derived'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ const AbstractMetaClass *base = AbstractMetaClass::findClass(classes, QLatin1String("Base"));
+ QCOMPARE(base->hasNonPrivateConstructor(), true);
+ const AbstractMetaClass *derived = AbstractMetaClass::findClass(classes, QLatin1String("Derived"));
+ QCOMPARE(derived->hasNonPrivateConstructor(), true);
+}
+
+QTEST_APPLESS_MAIN(TestCtorInformation)
diff --git a/sources/shiboken2/ApiExtractor/tests/testctorinformation.h b/sources/shiboken2/ApiExtractor/tests/testctorinformation.h
new file mode 100644
index 000000000..f5ffe5501
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testctorinformation.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTCTORINFORMATION_H
+#define TESTCTORINFORMATION_H
+
+#include <QObject>
+
+class AbstractMetaBuilder;
+
+class TestCtorInformation: public QObject
+{
+ Q_OBJECT
+private slots:
+ void testCtorIsPrivate();
+ void testHasNonPrivateCtor();
+};
+
+#endif // TESTCTORINFORMATION_H
diff --git a/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp
new file mode 100644
index 000000000..6b6c5d011
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.cpp
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testdroptypeentries.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+static const char* cppCode ="\
+ struct ValueA {};\n\
+ struct ValueB {};\n\
+ struct ObjectA {};\n\
+ struct ObjectB {};\n\
+ namespace NamespaceA {\n\
+ struct InnerClassA {};\n\
+ namespace InnerNamespaceA {}\n\
+ }\n\
+ namespace NamespaceB {}\n\
+ enum EnumA { Value0 };\n\
+ enum EnumB { Value1 };\n\
+ void funcA();\n\
+ void funcB();\n";
+
+static const char* xmlCode = "\
+<typesystem package='Foo'>\n\
+ <value-type name='ValueA'/>\n\
+ <value-type name='ValueB'/>\n\
+ <object-type name='ObjectA'/>\n\
+ <object-type name='ObjectB'/>\n\
+ <namespace-type name='NamespaceA'>\n\
+ <value-type name='InnerClassA'/>\n\
+ <namespace-type name='InnerNamespaceA'/>\n\
+ </namespace-type>\n\
+ <namespace-type name='NamespaceB'/>\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ <function signature='funcA()'/>\n\
+ <function signature='funcB()'/>\n\
+</typesystem>\n";
+
+void TestDropTypeEntries::testDropEntries()
+{
+ QStringList droppedEntries(QLatin1String("Foo.ValueB"));
+ droppedEntries << QLatin1String("Foo.ObjectB") << QLatin1String("Foo.NamespaceA.InnerClassA");
+ droppedEntries << QLatin1String("Foo.NamespaceB") << QLatin1String("Foo.EnumB") << QLatin1String("Foo.funcB()");
+ droppedEntries << QLatin1String("Foo.NamespaceA.InnerNamespaceA");
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, Q_NULLPTR, droppedEntries));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueA")));
+ QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("ValueB")));
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectA")));
+ QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("ObjectB")));
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA")));
+ QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA::InnerClassA")));
+ QVERIFY(!AbstractMetaClass::findClass(classes, QLatin1String("NamespaceB")));
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.count(), 1);
+ QCOMPARE(globalEnums.first()->name(), QLatin1String("EnumA"));
+
+ TypeDatabase* td = TypeDatabase::instance();
+ QVERIFY(td->findType(QLatin1String("funcA")));
+ QVERIFY(!td->findType(QLatin1String("funcB")));
+}
+
+void TestDropTypeEntries::testDontDropEntries()
+{
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueA")));
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ValueB")));
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectA")));
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("ObjectB")));
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA")));
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceA::InnerClassA")));
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("NamespaceB")));
+
+ QCOMPARE(builder->globalEnums().size(), 2);
+
+ TypeDatabase* td = TypeDatabase::instance();
+ QVERIFY(td->findType(QLatin1String("funcA")));
+ QVERIFY(td->findType(QLatin1String("funcB")));
+}
+
+static const char* cppCode2 ="\
+ struct ValueA {\n\
+ void func();\n\
+ };\n";
+
+static const char* xmlCode2 = "\
+<typesystem package='Foo'>\n\
+ <value-type name='ValueA'>\n\
+ <modify-function signature='func()'>\n\
+ <remove class='all'/>\n\
+ </modify-function>\n\
+ </value-type>\n\
+</typesystem>\n";
+
+void TestDropTypeEntries::testDropEntryWithChildTags()
+{
+ QStringList droppedEntries(QLatin1String("Foo.ValueA"));
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false, Q_NULLPTR, droppedEntries));
+ QVERIFY(!builder.isNull());
+ QVERIFY(!AbstractMetaClass::findClass(builder->classes(), QLatin1String("ValueA")));
+}
+
+
+void TestDropTypeEntries::testDontDropEntryWithChildTags()
+{
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false));
+ QVERIFY(!builder.isNull());
+ QVERIFY(AbstractMetaClass::findClass(builder->classes(), QLatin1String("ValueA")));
+}
+
+QTEST_APPLESS_MAIN(TestDropTypeEntries)
diff --git a/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.h b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.h
new file mode 100644
index 000000000..d04c6dc92
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testdroptypeentries.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTDROPTYPEENTRIES_H
+#define TESTDROPTYPEENTRIES_H
+
+#include <QObject>
+
+class TestDropTypeEntries : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testDropEntries();
+ void testDontDropEntries();
+ void testDropEntryWithChildTags();
+ void testDontDropEntryWithChildTags();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp
new file mode 100644
index 000000000..63b745c12
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.cpp
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testdtorinformation.h"
+#include "abstractmetabuilder.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestDtorInformation::testDtorIsPrivate()
+{
+ const char* cppCode ="class Control { public: ~Control() {} }; class Subject { private: ~Subject() {} };";
+ const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"Control\"/><value-type name=\"Subject\"/></typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasPrivateDestructor(), false);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasPrivateDestructor(), true);
+}
+
+void TestDtorInformation::testDtorIsProtected()
+{
+ const char* cppCode ="class Control { public: ~Control() {} }; class Subject { protected: ~Subject() {} };";
+ const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"Control\"/><value-type name=\"Subject\"/></typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasProtectedDestructor(), false);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasProtectedDestructor(), true);
+}
+
+void TestDtorInformation::testDtorIsVirtual()
+{
+ const char* cppCode ="class Control { public: ~Control() {} }; class Subject { protected: virtual ~Subject() {} };";
+ const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"Control\"/><value-type name=\"Subject\"/></typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->hasVirtualDestructor(), false);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->hasVirtualDestructor(), true);
+}
+
+void TestDtorInformation::testClassWithVirtualDtorIsPolymorphic()
+{
+ const char* cppCode ="class Control { public: virtual ~Control() {} }; class Subject { protected: virtual ~Subject() {} };";
+ const char* xmlCode = "<typesystem package=\"Foo\"><value-type name=\"Control\"/><value-type name=\"Subject\"/></typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Control"))->isPolymorphic(), true);
+ QCOMPARE(AbstractMetaClass::findClass(classes, QLatin1String("Subject"))->isPolymorphic(), true);
+}
+
+QTEST_APPLESS_MAIN(TestDtorInformation)
+
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h
new file mode 100644
index 000000000..21a3b1822
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testdtorinformation.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTDTORINFORMATION_H
+#define TESTDTORINFORMATION_H
+
+#include <QObject>
+
+class AbstractMetaBuilder;
+
+class TestDtorInformation: public QObject
+{
+ Q_OBJECT
+private slots:
+ void testDtorIsPrivate();
+ void testDtorIsProtected();
+ void testDtorIsVirtual();
+ void testClassWithVirtualDtorIsPolymorphic();
+};
+
+#endif // TESTDTORINFORMATION_H
diff --git a/sources/shiboken2/ApiExtractor/tests/testenum.cpp b/sources/shiboken2/ApiExtractor/tests/testenum.cpp
new file mode 100644
index 000000000..98e56b86e
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testenum.cpp
@@ -0,0 +1,416 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testenum.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestEnum::testEnumCppSignature()
+{
+ const char* cppCode ="\
+ enum GlobalEnum { A, B };\n\
+ \n\
+ struct A {\n\
+ enum ClassEnum { CA, CB };\n\
+ void method(ClassEnum);\n\
+ };\n\
+ void func(A::ClassEnum);\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='GlobalEnum'/>\n\
+ <value-type name='A'>\n\
+ <enum-type name='ClassEnum'/>\n\
+ </value-type>\n\
+ <function signature='func(A::ClassEnum)'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.count(), 1);
+ QCOMPARE(globalEnums.first()->name(), QLatin1String("GlobalEnum"));
+
+ // enum as parameter of a function
+ AbstractMetaFunctionList functions = builder->globalFunctions();
+ QCOMPARE(functions.count(), 1);
+ QCOMPARE(functions.first()->arguments().count(), 1);
+ QCOMPARE(functions.first()->arguments().first()->type()->cppSignature(), QLatin1String("A::ClassEnum"));
+
+ // enum as parameter of a method
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QCOMPARE(classA->enums().count(), 1);
+ AbstractMetaFunctionList funcs = classA->queryFunctionsByName(QLatin1String("method"));
+ QVERIFY(!funcs.isEmpty());
+ AbstractMetaFunction* method = funcs.first();
+ QVERIFY(method);
+ AbstractMetaArgument* arg = method->arguments().first();
+ QCOMPARE(arg->type()->name(), QLatin1String("ClassEnum"));
+ QCOMPARE(arg->type()->cppSignature(), QLatin1String("A::ClassEnum"));
+ QCOMPARE(functions.first()->arguments().count(), 1);
+ arg = functions.first()->arguments().first();
+ QCOMPARE(arg->type()->name(), QLatin1String("ClassEnum"));
+ QCOMPARE(arg->type()->cppSignature(), QLatin1String("A::ClassEnum"));
+
+ AbstractMetaEnumList classEnums = classA->enums();
+ QCOMPARE(classEnums.first()->name(), QLatin1String("ClassEnum"));
+}
+
+void TestEnum::testEnumWithApiVersion()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ enum ClassEnum { EnumA, EnumB };\n\
+ enum ClassEnum2 { EnumC, EnumD };\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='ClassEnum' since='0.1'/>\n\
+ <enum-type name='ClassEnum2' since='0.2'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, "0.1"));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+ QCOMPARE(classes[0]->enums().count(), 1);
+}
+
+void TestEnum::testAnonymousEnum()
+{
+ const char* cppCode ="\
+ enum { Global0, Global1 };\n\
+ struct A {\n\
+ enum { A0, A1 };\n\
+ enum { isThis = true, isThat = false };\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <!-- Uses the first value of the enum to identify it. -->\n\
+ <enum-type identified-by-value='Global0'/>\n\
+ <value-type name='A'>\n\
+ <!-- Uses the second value of the enum to identify it. -->\n\
+ <enum-type identified-by-value='A1'/>\n\
+ <enum-type identified-by-value='isThis'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.count(), 1);
+ QCOMPARE(globalEnums.first()->typeEntry()->qualifiedCppName(), QLatin1String("Global0"));
+ QVERIFY(globalEnums.first()->isAnonymous());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+ QCOMPARE(classes[0]->enums().count(), 2);
+
+ AbstractMetaEnum* anonEnumA1 = classes[0]->findEnum(QLatin1String("A1"));
+ QVERIFY(anonEnumA1);
+ QVERIFY(anonEnumA1->isAnonymous());
+ QCOMPARE(anonEnumA1->typeEntry()->qualifiedCppName(), QLatin1String("A::A1"));
+
+ AbstractMetaEnumValue* enumValueA0 = anonEnumA1->values().first();
+ QCOMPARE(enumValueA0->name(), QLatin1String("A0"));
+ QCOMPARE(enumValueA0->value(), 0);
+ QCOMPARE(enumValueA0->stringValue(), QString());
+
+ AbstractMetaEnumValue* enumValueA1 = anonEnumA1->values().last();
+ QCOMPARE(enumValueA1->name(), QLatin1String("A1"));
+ QCOMPARE(enumValueA1->value(), 1);
+ QCOMPARE(enumValueA1->stringValue(), QString());
+
+ AbstractMetaEnum* anonEnumIsThis = classes[0]->findEnum(QLatin1String("isThis"));
+ QVERIFY(anonEnumIsThis);
+ QVERIFY(anonEnumIsThis->isAnonymous());
+ QCOMPARE(anonEnumIsThis->typeEntry()->qualifiedCppName(), QLatin1String("A::isThis"));
+
+ AbstractMetaEnumValue* enumValueIsThis = anonEnumIsThis->values().first();
+ QCOMPARE(enumValueIsThis->name(), QLatin1String("isThis"));
+ QCOMPARE(enumValueIsThis->value(), static_cast<int>(true));
+ QCOMPARE(enumValueIsThis->stringValue(), QLatin1String("true"));
+
+ AbstractMetaEnumValue* enumValueIsThat = anonEnumIsThis->values().last();
+ QCOMPARE(enumValueIsThat->name(), QLatin1String("isThat"));
+ QCOMPARE(enumValueIsThat->value(), static_cast<int>(false));
+ QCOMPARE(enumValueIsThat->stringValue(), QLatin1String("false"));
+}
+
+void TestEnum::testGlobalEnums()
+{
+ const char* cppCode ="\
+ enum EnumA { A0, A1 };\n\
+ enum EnumB { B0 = 2, B1 = 0x4 };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.count(), 2);
+
+ AbstractMetaEnum* enumA = globalEnums.first();
+ QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("EnumA"));
+
+ AbstractMetaEnumValue* enumValueA0 = enumA->values().first();
+ QCOMPARE(enumValueA0->name(), QLatin1String("A0"));
+ QCOMPARE(enumValueA0->value(), 0);
+ QCOMPARE(enumValueA0->stringValue(), QString());
+
+ AbstractMetaEnumValue* enumValueA1 = enumA->values().last();
+ QCOMPARE(enumValueA1->name(), QLatin1String("A1"));
+ QCOMPARE(enumValueA1->value(), 1);
+ QCOMPARE(enumValueA1->stringValue(), QString());
+
+ AbstractMetaEnum* enumB = globalEnums.last();
+ QCOMPARE(enumB->typeEntry()->qualifiedCppName(), QLatin1String("EnumB"));
+
+ AbstractMetaEnumValue* enumValueB0 = enumB->values().first();
+ QCOMPARE(enumValueB0->name(), QLatin1String("B0"));
+ QCOMPARE(enumValueB0->value(), 2);
+ QCOMPARE(enumValueB0->stringValue(), QLatin1String("2"));
+
+ AbstractMetaEnumValue* enumValueB1 = enumB->values().last();
+ QCOMPARE(enumValueB1->name(), QLatin1String("B1"));
+ QCOMPARE(enumValueB1->value(), 4);
+ QCOMPARE(enumValueB1->stringValue(), QLatin1String("0x4"));
+}
+
+void TestEnum::testEnumValueFromNeighbourEnum()
+{
+ const char* cppCode ="\
+ namespace A {\n\
+ enum EnumA { ValueA0, ValueA1 };\n\
+ enum EnumB { ValueB0 = A::ValueA1, ValueB1 = ValueA0 };\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <namespace-type name='A'>\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+ QCOMPARE(classes[0]->enums().count(), 2);
+
+ AbstractMetaEnum* enumA = classes[0]->findEnum(QLatin1String("EnumA"));
+ QVERIFY(enumA);
+ QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumA"));
+
+ AbstractMetaEnumValue* enumValueA0 = enumA->values().first();
+ QCOMPARE(enumValueA0->name(), QLatin1String("ValueA0"));
+ QCOMPARE(enumValueA0->value(), 0);
+ QCOMPARE(enumValueA0->stringValue(), QString());
+
+ AbstractMetaEnumValue* enumValueA1 = enumA->values().last();
+ QCOMPARE(enumValueA1->name(), QLatin1String("ValueA1"));
+ QCOMPARE(enumValueA1->value(), 1);
+ QCOMPARE(enumValueA1->stringValue(), QString());
+
+ AbstractMetaEnum* enumB = classes[0]->findEnum(QLatin1String("EnumB"));
+ QVERIFY(enumB);
+ QCOMPARE(enumB->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumB"));
+
+ AbstractMetaEnumValue* enumValueB0 = enumB->values().first();
+ QCOMPARE(enumValueB0->name(), QLatin1String("ValueB0"));
+ QCOMPARE(enumValueB0->value(), 1);
+ QCOMPARE(enumValueB0->stringValue(), QLatin1String("A::ValueA1"));
+
+ AbstractMetaEnumValue* enumValueB1 = enumB->values().last();
+ QCOMPARE(enumValueB1->name(), QLatin1String("ValueB1"));
+ QCOMPARE(enumValueB1->value(), 0);
+ QCOMPARE(enumValueB1->stringValue(), QLatin1String("ValueA0"));
+}
+
+void TestEnum::testEnumValueFromExpression()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ enum EnumA {\n\
+ ValueA0 = 3u,\n\
+ ValueA1 = ~3u,\n\
+ ValueA2 = ~3,\n\
+ ValueA3 = 0xf0,\n\
+ ValueA4 = 8 |ValueA3,\n\
+ ValueA5 = ValueA3|32,\n\
+ ValueA6 = ValueA3 >> 1,\n\
+ ValueA7 = ValueA3 << 1\n\
+ };\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='EnumA'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
+ QVERIFY(classA);
+
+ AbstractMetaEnum* enumA = classA->findEnum(QLatin1String("EnumA"));
+ QVERIFY(enumA);
+ QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("A::EnumA"));
+
+ AbstractMetaEnumValue* valueA0 = enumA->values().at(0);
+ QCOMPARE(valueA0->name(), QLatin1String("ValueA0"));
+ QCOMPARE(valueA0->stringValue(), QLatin1String("3u"));
+ QCOMPARE(valueA0->value(), (int) 3u);
+
+ AbstractMetaEnumValue* valueA1 = enumA->values().at(1);
+ QCOMPARE(valueA1->name(), QLatin1String("ValueA1"));
+ QCOMPARE(valueA1->stringValue(), QLatin1String("~3u"));
+ QCOMPARE(valueA1->value(), (int) ~3u);
+
+ AbstractMetaEnumValue* valueA2 = enumA->values().at(2);
+ QCOMPARE(valueA2->name(), QLatin1String("ValueA2"));
+ QCOMPARE(valueA2->stringValue(), QLatin1String("~3"));
+ QCOMPARE(valueA2->value(), ~3);
+
+ AbstractMetaEnumValue* valueA3 = enumA->values().at(3);
+ QCOMPARE(valueA3->name(), QLatin1String("ValueA3"));
+ QCOMPARE(valueA3->stringValue(), QLatin1String("0xf0"));
+ QCOMPARE(valueA3->value(), 0xf0);
+
+ AbstractMetaEnumValue* valueA4 = enumA->values().at(4);
+ QCOMPARE(valueA4->name(), QLatin1String("ValueA4"));
+ QCOMPARE(valueA4->stringValue(), QLatin1String("8 |ValueA3"));
+ QCOMPARE(valueA4->value(), 8|0xf0);
+
+ AbstractMetaEnumValue* valueA5 = enumA->values().at(5);
+ QCOMPARE(valueA5->name(), QLatin1String("ValueA5"));
+ QCOMPARE(valueA5->stringValue(), QLatin1String("ValueA3|32"));
+ QCOMPARE(valueA5->value(), 0xf0|32);
+
+ AbstractMetaEnumValue* valueA6 = enumA->values().at(6);
+ QCOMPARE(valueA6->name(), QLatin1String("ValueA6"));
+ QCOMPARE(valueA6->stringValue(), QLatin1String("ValueA3 >> 1"));
+ QCOMPARE(valueA6->value(), 0xf0 >> 1);
+
+ AbstractMetaEnumValue* valueA7 = enumA->values().at(7);
+ QCOMPARE(valueA7->name(), QLatin1String("ValueA7"));
+ QCOMPARE(valueA7->stringValue(), QLatin1String("ValueA3 << 1"));
+ QCOMPARE(valueA7->value(), 0xf0 << 1);
+}
+
+void TestEnum::testPrivateEnum()
+{
+ const char* cppCode ="\
+ class A {\n\
+ private:\n\
+ enum PrivateEnum { Priv0 = 0x0f, Priv1 = 0xf0 };\n\
+ public:\n\
+ enum PublicEnum { Pub0 = Priv0, Pub1 = A::Priv1 };\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='PublicEnum'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->enums().count(), 2);
+
+ AbstractMetaEnum* privateEnum = classA->findEnum(QLatin1String("PrivateEnum"));
+ QVERIFY(privateEnum);
+ QVERIFY(privateEnum->isPrivate());
+ QCOMPARE(privateEnum->typeEntry()->qualifiedCppName(), QLatin1String("A::PrivateEnum"));
+
+ AbstractMetaEnum* publicEnum = classA->findEnum(QLatin1String("PublicEnum"));
+ QVERIFY(publicEnum);
+ QCOMPARE(publicEnum->typeEntry()->qualifiedCppName(), QLatin1String("A::PublicEnum"));
+
+ AbstractMetaEnumValue* pub0 = publicEnum->values().first();
+ QCOMPARE(pub0->name(), QLatin1String("Pub0"));
+ QCOMPARE(pub0->value(), 0x0f);
+ QCOMPARE(pub0->stringValue(), QLatin1String("Priv0"));
+
+ AbstractMetaEnumValue* pub1 = publicEnum->values().last();
+ QCOMPARE(pub1->name(), QLatin1String("Pub1"));
+ QCOMPARE(pub1->value(), 0xf0);
+ QCOMPARE(pub1->stringValue(), QLatin1String("A::Priv1"));
+}
+
+void TestEnum::testTypedefEnum()
+{
+ const char* cppCode ="\
+ typedef enum EnumA {\n\
+ A0,\n\
+ A1,\n\
+ } EnumA;\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='EnumA'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QEXPECT_FAIL("", "APIExtractor does not handle typedef enum correctly yet", Abort);
+ QCOMPARE(globalEnums.count(), 1);
+
+ AbstractMetaEnum* enumA = globalEnums.first();
+ QCOMPARE(enumA->typeEntry()->qualifiedCppName(), QLatin1String("EnumA"));
+
+ AbstractMetaEnumValue* enumValueA0 = enumA->values().first();
+ QCOMPARE(enumValueA0->name(), QLatin1String("A0"));
+ QCOMPARE(enumValueA0->value(), 0);
+ QCOMPARE(enumValueA0->stringValue(), QLatin1String(""));
+
+ AbstractMetaEnumValue* enumValueA1 = enumA->values().last();
+ QCOMPARE(enumValueA1->name(), QLatin1String("A1"));
+ QCOMPARE(enumValueA1->value(), 1);
+ QCOMPARE(enumValueA1->stringValue(), QString());
+}
+
+QTEST_APPLESS_MAIN(TestEnum)
diff --git a/sources/shiboken2/ApiExtractor/tests/testenum.h b/sources/shiboken2/ApiExtractor/tests/testenum.h
new file mode 100644
index 000000000..8b46b1bd6
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testenum.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTENUM_H
+#define TESTENUM_H
+#include <QObject>
+
+class TestEnum : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testEnumCppSignature();
+ void testEnumWithApiVersion();
+ void testAnonymousEnum();
+ void testGlobalEnums();
+ void testEnumValueFromNeighbourEnum();
+ void testEnumValueFromExpression();
+ void testPrivateEnum();
+ void testTypedefEnum();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testextrainclude.cpp b/sources/shiboken2/ApiExtractor/tests/testextrainclude.cpp
new file mode 100644
index 000000000..97f0d568e
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testextrainclude.cpp
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testextrainclude.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestExtraInclude::testClassExtraInclude()
+{
+ const char* cppCode ="struct A {};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <extra-includes>\n\
+ <include file-name='header.h' location='global'/>\n\
+ </extra-includes>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+
+ QVector<Include> includes = classA->typeEntry()->extraIncludes();
+ QCOMPARE(includes.count(), 1);
+ QCOMPARE(includes.first().name(), QLatin1String("header.h"));
+}
+
+void TestExtraInclude::testGlobalExtraIncludes()
+{
+ const char* cppCode ="struct A {};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <extra-includes>\n\
+ <include file-name='header1.h' location='global'/>\n\
+ <include file-name='header2.h' location='global'/>\n\
+ </extra-includes>\n\
+ <value-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, QLatin1String("A")));
+
+ TypeDatabase* td = TypeDatabase::instance();
+ TypeEntry* module = td->findType(QLatin1String("Foo"));
+ QVERIFY(module);
+
+ QVector<Include> includes = module->extraIncludes();
+ QCOMPARE(includes.count(), 2);
+ QCOMPARE(includes.first().name(), QLatin1String("header1.h"));
+ QCOMPARE(includes.last().name(), QLatin1String("header2.h"));
+}
+
+QTEST_APPLESS_MAIN(TestExtraInclude)
diff --git a/sources/shiboken2/ApiExtractor/tests/testextrainclude.h b/sources/shiboken2/ApiExtractor/tests/testextrainclude.h
new file mode 100644
index 000000000..c569901e1
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testextrainclude.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTEXTRAINCLUDE_H
+#define TESTEXTRAINCLUDE_H
+
+#include <QObject>
+
+class TestExtraInclude : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testClassExtraInclude();
+ void testGlobalExtraIncludes();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testfunctiontag.cpp b/sources/shiboken2/ApiExtractor/tests/testfunctiontag.cpp
new file mode 100644
index 000000000..a29d740bf
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testfunctiontag.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testfunctiontag.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestFunctionTag::testFunctionTagForSpecificSignature()
+{
+ const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='float'/>\n\
+ <function signature='globalFunction(int)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("globalFunction"));
+ QVERIFY(func);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+}
+
+void TestFunctionTag::testFunctionTagForAllSignatures()
+{
+ const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='float'/>\n\
+ <function signature='globalFunction(int)'/>\n\
+ <function signature='globalFunction(float)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("globalFunction"));
+ QVERIFY(func);
+ QCOMPARE(builder->globalFunctions().size(), 2);
+}
+
+void TestFunctionTag::testRenameGlobalFunction()
+{
+ const char* cppCode ="void global_function_with_ugly_name();\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <function signature='global_function_with_ugly_name()' rename='smooth'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ const TypeEntry *func = TypeDatabase::instance()->findType(QLatin1String("global_function_with_ugly_name"));
+ QVERIFY(func);
+
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ const AbstractMetaFunction* metaFunc = builder->globalFunctions().first();
+
+ QVERIFY(metaFunc);
+ QCOMPARE(metaFunc->modifications().size(), 1);
+ QVERIFY(metaFunc->modifications().first().isRenameModifier());
+ QCOMPARE(metaFunc->modifications().first().renamedTo(), QLatin1String("smooth"));
+
+ QCOMPARE(metaFunc->name(), QLatin1String("smooth"));
+ QCOMPARE(metaFunc->originalName(), QLatin1String("global_function_with_ugly_name"));
+ QCOMPARE(metaFunc->minimalSignature(), QLatin1String("global_function_with_ugly_name()"));
+}
+
+QTEST_APPLESS_MAIN(TestFunctionTag)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testfunctiontag.h b/sources/shiboken2/ApiExtractor/tests/testfunctiontag.h
new file mode 100644
index 000000000..d4b6c7d2c
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testfunctiontag.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTFUNCTIONTAG_H
+#define TESTFUNCTIONTAG_H
+#include <QObject>
+
+class TestFunctionTag : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testFunctionTagForSpecificSignature();
+ void testFunctionTagForAllSignatures();
+ void testRenameGlobalFunction();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.cpp b/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.cpp
new file mode 100644
index 000000000..7e8db42f3
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.cpp
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testimplicitconversions.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+#include <QtTest/QTest>
+
+void TestImplicitConversions::testWithPrivateCtors()
+{
+ const char* cppCode ="\
+ class B;\n\
+ class C;\n\
+ class A {\n\
+ A(const B&);\n\
+ public:\n\
+ A(const C&);\n\
+ };\n\
+ class B {};\n\
+ class C {};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 3);
+
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C"));
+ AbstractMetaFunctionList implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.count(), 1);
+ QCOMPARE(implicitConvs.first()->arguments().first()->type()->typeEntry(), classC->typeEntry());
+}
+
+void TestImplicitConversions::testWithModifiedVisibility()
+{
+ const char* cppCode ="\
+ class B;\n\
+ class A {\n\
+ public:\n\
+ A(const B&);\n\
+ };\n\
+ class B {};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <modify-function signature='A(const B&amp;)'>\n\
+ <access modifier='private'/>\n\
+ </modify-function>\n\
+ </value-type>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ AbstractMetaFunctionList implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.count(), 1);
+ QCOMPARE(implicitConvs.first()->arguments().first()->type()->typeEntry(), classB->typeEntry());
+}
+
+
+void TestImplicitConversions::testWithAddedCtor()
+{
+ const char* cppCode ="\
+ class B;\n\
+ class A {\n\
+ public:\n\
+ A(const B&);\n\
+ };\n\
+ class B {};\n\
+ class C {};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <custom-type name='TARGETLANGTYPE'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='A(const C&amp;)'/>\n\
+ </value-type>\n\
+ <value-type name='B'>\n\
+ <add-function signature='B(TARGETLANGTYPE*)'/>\n\
+ </value-type>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 3);
+
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ AbstractMetaFunctionList implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.count(), 2);
+
+ // Added constructors with custom types should never result in implicit converters.
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ implicitConvs = classB->implicitConversions();
+ QCOMPARE(implicitConvs.count(), 0);
+}
+
+void TestImplicitConversions::testWithExternalConversionOperator()
+{
+ const char* cppCode ="\
+ class A {};\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char* xmlCode = "\n\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ AbstractMetaFunctionList implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.count(), 1);
+ AbstractMetaFunctionList externalConvOps = classA->externalConversionOperators();
+ QCOMPARE(externalConvOps.count(), 1);
+
+ const AbstractMetaFunction* convOp = 0;
+ for (const AbstractMetaFunction *func : classB->functions()) {
+ if (func->isConversionOperator())
+ convOp = func;
+ }
+ QVERIFY(convOp);
+ QCOMPARE(implicitConvs.first(), convOp);
+}
+
+QTEST_APPLESS_MAIN(TestImplicitConversions)
diff --git a/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.h b/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.h
new file mode 100644
index 000000000..657c1a558
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testimplicitconversions.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTIMPLICITCONVERSIONS_H
+#define TESTIMPLICITCONVERSIONS_H
+
+#include <QObject>
+
+class AbstractMetaBuilder;
+
+class TestImplicitConversions : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testWithPrivateCtors();
+ void testWithModifiedVisibility();
+ void testWithAddedCtor();
+ void testWithExternalConversionOperator();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testinserttemplate.cpp b/sources/shiboken2/ApiExtractor/tests/testinserttemplate.cpp
new file mode 100644
index 000000000..ecadf311b
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testinserttemplate.cpp
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testinserttemplate.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestInsertTemplate::testInsertTemplateOnClassInjectCode()
+{
+ const char* cppCode ="struct A{};\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <template name='code_template'>\n\
+ code template content\n\
+ </template>\n\
+ <value-type name='A'>\n\
+ <inject-code class='native'>\n\
+ <insert-template name='code_template'/>\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->typeEntry()->codeSnips().count(), 1);
+ QString code = classA->typeEntry()->codeSnips().first().code();
+ QVERIFY(code.contains(QLatin1String("code template content")));
+}
+
+void TestInsertTemplate::testInsertTemplateOnModuleInjectCode()
+{
+ const char* cppCode ="";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <template name='code_template'>\n\
+ code template content\n\
+ </template>\n\
+ <inject-code class='native'>\n\
+ <insert-template name='code_template'/>\n\
+ </inject-code>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(classes.isEmpty());
+
+ TypeEntry* module = TypeDatabase::instance()->findType(QLatin1String("Foo"));
+ QVERIFY(module);
+ QCOMPARE(module->codeSnips().count(), 1);
+ QString code = module->codeSnips().first().code().trimmed();
+ QVERIFY(code.contains(QLatin1String("code template content")));
+}
+
+void TestInsertTemplate::testInvalidTypeSystemTemplate()
+{
+ const char* cppCode ="";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <inject-code class='native'>\n\
+ <insert-template name='this_code_template_does_not_exists'/>\n\
+ </inject-code>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(classes.isEmpty());
+
+ TypeEntry* module = TypeDatabase::instance()->findType(QLatin1String("Foo"));
+ QVERIFY(module);
+ QCOMPARE(module->codeSnips().count(), 1);
+ QString code = module->codeSnips().first().code().trimmed();
+ QVERIFY(code.isEmpty());
+}
+
+void TestInsertTemplate::testValidAndInvalidTypeSystemTemplate()
+{
+ const char* cppCode ="";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <template name='code_template'>\n\
+ code template content\n\
+ </template>\n\
+ <inject-code class='native'>\n\
+ <insert-template name='this_code_template_does_not_exists'/>\n\
+ <insert-template name='code_template'/>\n\
+ </inject-code>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(classes.isEmpty());
+
+ TypeEntry* module = TypeDatabase::instance()->findType(QLatin1String("Foo"));
+ QVERIFY(module);
+ QCOMPARE(module->codeSnips().count(), 1);
+ QString code = module->codeSnips().first().code().trimmed();
+ QVERIFY(code.contains(QLatin1String("code template content")));
+}
+
+QTEST_APPLESS_MAIN(TestInsertTemplate)
diff --git a/sources/shiboken2/ApiExtractor/tests/testinserttemplate.h b/sources/shiboken2/ApiExtractor/tests/testinserttemplate.h
new file mode 100644
index 000000000..0e2a882fe
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testinserttemplate.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTINSERTTEMPLATE_H
+#define TESTINSERTTEMPLATE_H
+
+#include <QObject>
+
+class TestInsertTemplate : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testInsertTemplateOnClassInjectCode();
+ void testInsertTemplateOnModuleInjectCode();
+ void testInvalidTypeSystemTemplate();
+ void testValidAndInvalidTypeSystemTemplate();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
new file mode 100644
index 000000000..96bd0251b
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testmodifydocumentation.h"
+
+#include <QCoreApplication>
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+#include <qtdocparser.h>
+
+void TestModifyDocumentation::testModifyDocumentation()
+{
+ const char* cppCode ="struct B { void b(); }; class A {};\n";
+ const char* xmlCode = "<typesystem package=\"Foo\">\n\
+ <value-type name='B'>\n\
+ <modify-function signature='b()' remove='all'/>\n\
+ </value-type>\n\
+ <value-type name='A'>\n\
+ <modify-documentation xpath='description/para[3]'>\n\
+ &lt;para>Some changed contents here&lt;/para>\n\
+ </modify-documentation>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClass *classA = AbstractMetaClass::findClass(builder->classes(), QLatin1String("A"));
+ QVERIFY(classA);
+ DocModificationList docMods = classA->typeEntry()->docModifications();
+ QCOMPARE(docMods.count(), 1);
+ QCOMPARE(docMods[0].code().trimmed(), QLatin1String("<para>Some changed contents here</para>"));
+ QCOMPARE(docMods[0].signature(), QString());
+ QtDocParser docParser;
+ docParser.setDocumentationDataDirectory(QDir::currentPath());
+ docParser.fillDocumentation(classA);
+
+ QVERIFY(!classA->documentation().value().trimmed().isEmpty());
+ QCOMPARE(classA->documentation().value(), QLatin1String("<?xml version=\"1.0\"?>\n\
+<description>oi\n\
+ <para>Paragraph number 1</para>\n\
+ <para>Paragraph number 2</para>\n\
+ <para>Some changed contents here</para>\n\
+</description>\n"));
+}
+
+// We expand QTEST_MAIN macro but using QCoreApplication instead of QApplication
+// because this test needs an event loop but can't use QApplication to avoid a crash
+// on our ARMEL/FRAMANTLE buildbot
+int main(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+ TestModifyDocumentation tc;
+ return QTest::qExec(&tc, argc, argv);
+}
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.h b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.h
new file mode 100644
index 000000000..fb8f6fc01
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifydocumentation.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTMODIFYDOCUMENTATION_H
+#define TESTMODIFYDOCUMENTATION_H
+
+#include <QObject>
+
+class TestModifyDocumentation : public QObject
+{
+Q_OBJECT
+private slots:
+ void testModifyDocumentation();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
new file mode 100644
index 000000000..3d4ef9c89
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.cpp
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testmodifyfunction.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestModifyFunction::testRenameArgument()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ void method(int=0);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='method(int)'>\n\
+ <modify-argument index='1'>\n\
+ <rename to='otherArg'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ const AbstractMetaFunction* func = classA->findFunction(QLatin1String("method"));
+ Q_ASSERT(func);
+
+ QCOMPARE(func->argumentName(1), QLatin1String("otherArg"));
+}
+
+void TestModifyFunction::testOwnershipTransfer()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ struct B {\n\
+ virtual A* method();\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A' />\n\
+ <object-type name='B'>\n\
+ <modify-function signature='method()'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ const AbstractMetaFunction* func = classB->findFunction(QLatin1String("method"));
+
+ QCOMPARE(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0), TypeSystem::CppOwnership);
+}
+
+
+void TestModifyFunction::invalidateAfterUse()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ virtual void call(int *a);\n\
+ };\n\
+ struct B : A {\n\
+ };\n\
+ struct C : B {\n\
+ virtual void call2(int *a);\n\
+ };\n\
+ struct D : C {\n\
+ virtual void call2(int *a);\n\
+ };\n\
+ struct E : D {\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='call(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='B' />\n\
+ <object-type name='C'>\n\
+ <modify-function signature='call2(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='D'>\n\
+ <modify-function signature='call2(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='E' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ const AbstractMetaFunction* func = classB->findFunction(QLatin1String("call"));
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods.size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse);
+
+ const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C"));
+ QVERIFY(classC);
+ func = classC->findFunction(QLatin1String("call"));
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods.size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse);
+
+ func = classC->findFunction(QLatin1String("call2"));
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods.size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse);
+
+ const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("D"));
+ QVERIFY(classD);
+ func = classD->findFunction(QLatin1String("call"));
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods.size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse);
+
+ func = classD->findFunction(QLatin1String("call2"));
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods.size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse);
+
+ const AbstractMetaClass *classE = AbstractMetaClass::findClass(classes, QLatin1String("E"));
+ QVERIFY(classE);
+ func = classE->findFunction(QLatin1String("call"));
+ QVERIFY(func);
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods.size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse);
+
+ func = classE->findFunction(QLatin1String("call2"));
+ QVERIFY(func);
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods.size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods.at(0).resetAfterUse);
+}
+
+void TestModifyFunction::testWithApiVersion()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ struct B {\n\
+ virtual A* method();\n\
+ virtual B* methodB();\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A' />\n\
+ <object-type name='B'>\n\
+ <modify-function signature='method()' since='0.1'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ <modify-function signature='methodB()' since='0.2'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ const AbstractMetaFunction* func = classB->findFunction(QLatin1String("method"));
+
+ QCOMPARE(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0), TypeSystem::CppOwnership);
+
+ func = classB->findFunction(QLatin1String("methodB"));
+ QVERIFY(func->ownership(func->ownerClass(), TypeSystem::TargetLangCode, 0) != TypeSystem::CppOwnership);
+}
+
+void TestModifyFunction::testGlobalFunctionModification()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ void function(A* a = 0);\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='A'/>\n\
+ <function signature='function(A*)'>\n\
+ <modify-function signature='function(A*)'>\n\
+ <modify-argument index='1'>\n\
+ <replace-type modified-type='A'/>\n\
+ <replace-default-expression with='A()'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </function>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ QCOMPARE(builder->globalFunctions().size(), 1);
+
+ FunctionModificationList mods = TypeDatabase::instance()->functionModifications(QLatin1String("function(A*)"));
+ QCOMPARE(mods.count(), 1);
+ QVector<ArgumentModification> argMods = mods.first().argument_mods;
+ QCOMPARE(argMods.count(), 1);
+ ArgumentModification argMod = argMods.first();
+ QCOMPARE(argMod.replacedDefaultExpression, QLatin1String("A()"));
+
+ const AbstractMetaFunction* func = builder->globalFunctions().first();
+ QVERIFY(func);
+ QCOMPARE(func->arguments().count(), 1);
+ const AbstractMetaArgument* arg = func->arguments().first();
+ QCOMPARE(arg->type()->cppSignature(), QLatin1String("A *"));
+ QCOMPARE(arg->originalDefaultValueExpression(), QLatin1String("0"));
+ QCOMPARE(arg->defaultValueExpression(), QLatin1String("A()"));
+}
+
+QTEST_APPLESS_MAIN(TestModifyFunction)
diff --git a/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
new file mode 100644
index 000000000..fcaa0f9db
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testmodifyfunction.h
@@ -0,0 +1,45 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTABSTRACTMETACLASS_H
+#define TESTABSTRACTMETACLASS_H
+
+#include <QObject>
+
+class TestModifyFunction : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testOwnershipTransfer();
+ void testWithApiVersion();
+ void testRenameArgument();
+ void invalidateAfterUse();
+ void testGlobalFunctionModification();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp
new file mode 100644
index 000000000..b78e6ec01
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testmultipleinheritance.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestMultipleInheritance::testVirtualClass()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ virtual ~A();\n\
+ virtual void theBug();\n\
+ };\n\
+ struct B {\n\
+ virtual ~B();\n\
+ };\n\
+ struct C : A, B {\n\
+ };\n\
+ struct D : C {\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A' />\n\
+ <object-type name='B' />\n\
+ <object-type name='C' />\n\
+ <object-type name='D' />\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 4);
+
+ const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("D"));
+ bool functionFound = false;
+ const AbstractMetaFunctionList &functions = classD->functions();
+ for (AbstractMetaFunction *f : functions) {
+ if (f->name() == QLatin1String("theBug")) {
+ functionFound = true;
+ break;
+ }
+ }
+ QVERIFY(functionFound);
+
+}
+
+QTEST_APPLESS_MAIN(TestMultipleInheritance)
diff --git a/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.h b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.h
new file mode 100644
index 000000000..2313073bb
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTMULTIPLEINHERITANCE_H
+#define TESTMULTIPLEINHERITANCE_H
+
+#include <QObject>
+
+class AbstractMetaBuilder;
+
+class TestMultipleInheritance : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testVirtualClass();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testnamespace.cpp b/sources/shiboken2/ApiExtractor/tests/testnamespace.cpp
new file mode 100644
index 000000000..ca6ce0589
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testnamespace.cpp
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testnamespace.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void NamespaceTest::testNamespaceMembers()
+{
+ const char* cppCode = "\
+ namespace Namespace\n\
+ {\n\
+ enum Option {\n\
+ OpZero,\n\
+ OpOne\n\
+ };\n\
+ void foo(Option opt);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='Namespace'>\n\
+ <enum-type name='Option' />\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClass *ns = AbstractMetaClass::findClass(classes, QLatin1String("Namespace"));
+ QVERIFY(ns);
+ const AbstractMetaEnum* metaEnum = ns->findEnum(QLatin1String("Option"));
+ QVERIFY(metaEnum);
+ const AbstractMetaFunction* func = ns->findFunction(QLatin1String("foo"));
+ QVERIFY(func);
+}
+
+void NamespaceTest::testNamespaceInnerClassMembers()
+{
+ const char* cppCode = "\
+ namespace OuterNamespace\n\
+ {\n\
+ namespace InnerNamespace {\n\
+ struct SomeClass {\n\
+ void method();\n\
+ };\n\
+ };\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='OuterNamespace'>\n\
+ <namespace-type name='InnerNamespace'>\n\
+ <value-type name='SomeClass'/>\n\
+ </namespace-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *ons = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace"));
+ QVERIFY(ons);
+ const AbstractMetaClass *ins = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace"));
+ QVERIFY(ins);
+ const AbstractMetaClass *sc = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace::SomeClass"));
+ QVERIFY(sc);
+ const AbstractMetaFunction* meth = sc->findFunction(QLatin1String("method"));
+ QVERIFY(meth);
+}
+
+QTEST_APPLESS_MAIN(NamespaceTest)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testnamespace.h b/sources/shiboken2/ApiExtractor/tests/testnamespace.h
new file mode 100644
index 000000000..d4451a938
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testnamespace.h
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTNAMESPACE_H
+#define TESTNAMESPACE_H
+
+#include <QObject>
+
+// The class is named 'NamespaceTest' to avoid clashes with Qt COIN using
+// '-qtnamespace TestNamespace'.
+class NamespaceTest : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testNamespaceMembers();
+ void testNamespaceInnerClassMembers();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testnestedtypes.cpp b/sources/shiboken2/ApiExtractor/tests/testnestedtypes.cpp
new file mode 100644
index 000000000..296aa4385
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testnestedtypes.cpp
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testnestedtypes.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestNestedTypes::testNestedTypesModifications()
+{
+ const char* cppCode ="\
+ namespace OuterNamespace {\n\
+ namespace InnerNamespace {\n\
+ struct SomeClass {\n\
+ void method() {}\n\
+ };\n\
+ };\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='OuterNamespace'>\n\
+ <namespace-type name='InnerNamespace'>\n\
+ <inject-code class='native'>custom_code1();</inject-code>\n\
+ <add-function signature='method()' return-type='OuterNamespace::InnerNamespace::SomeClass'>\n\
+ <inject-code class='target'>custom_code2();</inject-code>\n\
+ </add-function>\n\
+ <object-type name='SomeClass' target-lang-name='RenamedSomeClass'>\n\
+ <modify-function signature='method()' remove='all'/>\n\
+ </object-type>\n\
+ </namespace-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+
+ const AbstractMetaClass *ons = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace"));
+ QVERIFY(ons);
+
+ const AbstractMetaClass *ins = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace"));
+ QVERIFY(ins);
+ QCOMPARE(ins->functions().count(), 1);
+ QCOMPARE(ins->typeEntry()->codeSnips().count(), 1);
+ CodeSnip snip = ins->typeEntry()->codeSnips().first();
+ QCOMPARE(snip.code(), QLatin1String("custom_code1();"));
+
+ AbstractMetaFunction* addedFunc = ins->functions().first();
+ QVERIFY(addedFunc->isUserAdded());
+ QCOMPARE(addedFunc->visibility(), AbstractMetaFunction::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QCOMPARE(addedFunc->type()->minimalSignature(), QLatin1String("OuterNamespace::InnerNamespace::SomeClass"));
+
+ QCOMPARE(addedFunc->modifications().size(), 1);
+ QVERIFY(addedFunc->modifications().first().isCodeInjection());
+ snip = addedFunc->modifications().first().snips.first();
+ QCOMPARE(snip.code(), QLatin1String("custom_code2();"));
+
+ const AbstractMetaClass *sc = AbstractMetaClass::findClass(classes, QLatin1String("OuterNamespace::InnerNamespace::SomeClass"));
+ QVERIFY(ins);
+ QCOMPARE(sc->functions().count(), 2); // default constructor and removed method
+ AbstractMetaFunction* removedFunc = sc->functions().last();
+ QVERIFY(removedFunc->isModifiedRemoved());
+}
+
+
+void TestNestedTypes::testDuplicationOfNestedTypes()
+{
+ const char* cppCode ="\
+ namespace Namespace {\n\
+ class SomeClass {};\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='Namespace'>\n\
+ <value-type name='SomeClass'>\n\
+ <add-function signature='createSomeClass(Namespace::SomeClass)'/>\n\
+ </value-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 2);
+ const AbstractMetaClass *nspace = AbstractMetaClass::findClass(classes, QLatin1String("Namespace"));
+ QVERIFY(nspace);
+ const AbstractMetaClass *cls1 = AbstractMetaClass::findClass(classes, QLatin1String("SomeClass"));
+ QVERIFY(cls1);
+ const AbstractMetaClass *cls2 = AbstractMetaClass::findClass(classes, QLatin1String("Namespace::SomeClass"));
+ QVERIFY(cls2);
+ QCOMPARE(cls1, cls2);
+ QCOMPARE(cls1->name(), QLatin1String("SomeClass"));
+ QCOMPARE(cls1->qualifiedCppName(), QLatin1String("Namespace::SomeClass"));
+
+ TypeEntry* t1 = TypeDatabase::instance()->findType(QLatin1String("Namespace::SomeClass"));
+ QVERIFY(t1);
+ TypeEntry* t2 = TypeDatabase::instance()->findType(QLatin1String("SomeClass"));
+ QVERIFY(!t2);
+}
+
+QTEST_APPLESS_MAIN(TestNestedTypes)
diff --git a/sources/shiboken2/ApiExtractor/tests/testnestedtypes.h b/sources/shiboken2/ApiExtractor/tests/testnestedtypes.h
new file mode 100644
index 000000000..737e81fab
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testnestedtypes.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTNESTEDTYPES_H
+#define TESTNESTEDTYPES_H
+#include <QObject>
+
+class TestNestedTypes : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testNestedTypesModifications();
+ void testDuplicationOfNestedTypes();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.cpp b/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.cpp
new file mode 100644
index 000000000..3491d5cb4
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.cpp
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testnumericaltypedef.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestNumericalTypedef::testNumericalTypedef()
+{
+ const char* cppCode ="\
+ typedef double real;\n\
+ void funcDouble(double);\n\
+ void funcReal(real);\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <primitive-type name='real'/>\n\
+ <function signature='funcDouble(double)'/>\n\
+ <function signature='funcReal(real)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ QCOMPARE(builder->globalFunctions().size(), 2);
+ const AbstractMetaFunction* funcDouble = builder->globalFunctions().first();
+ QVERIFY(funcDouble);
+ const AbstractMetaFunction* funcReal = builder->globalFunctions().last();
+ QVERIFY(funcReal);
+
+ if (funcDouble->name() == QLatin1String("funcReal"))
+ std::swap(funcDouble, funcReal);
+
+ QCOMPARE(funcDouble->minimalSignature(), QLatin1String("funcDouble(double)"));
+ QCOMPARE(funcReal->minimalSignature(), QLatin1String("funcReal(real)"));
+
+ const AbstractMetaType* doubleType = funcDouble->arguments().first()->type();
+ QVERIFY(doubleType);
+ QCOMPARE(doubleType->cppSignature(), QLatin1String("double"));
+ QVERIFY(doubleType->isPrimitive());
+ QVERIFY(doubleType->typeEntry()->isCppPrimitive());
+
+ const AbstractMetaType* realType = funcReal->arguments().first()->type();
+ QVERIFY(realType);
+ QCOMPARE(realType->cppSignature(), QLatin1String("real"));
+ QVERIFY(realType->isPrimitive());
+ QVERIFY(realType->typeEntry()->isCppPrimitive());
+}
+
+void TestNumericalTypedef::testUnsignedNumericalTypedef()
+{
+ const char* cppCode ="\
+ typedef unsigned short ushort;\n\
+ void funcUnsignedShort(unsigned short);\n\
+ void funcUShort(ushort);\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='short'/>\n\
+ <primitive-type name='unsigned short'/>\n\
+ <primitive-type name='ushort'/>\n\
+ <function signature='funcUnsignedShort(unsigned short)'/>\n\
+ <function signature='funcUShort(ushort)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ QCOMPARE(builder->globalFunctions().size(), 2);
+ const AbstractMetaFunction* funcUnsignedShort = builder->globalFunctions().first();
+ QVERIFY(funcUnsignedShort);
+ const AbstractMetaFunction* funcUShort = builder->globalFunctions().last();
+ QVERIFY(funcUShort);
+
+ if (funcUnsignedShort->name() == QLatin1String("funcUShort"))
+ std::swap(funcUnsignedShort, funcUShort);
+
+ QCOMPARE(funcUnsignedShort->minimalSignature(), QLatin1String("funcUnsignedShort(unsigned short)"));
+ QCOMPARE(funcUShort->minimalSignature(), QLatin1String("funcUShort(ushort)"));
+
+ const AbstractMetaType* unsignedShortType = funcUnsignedShort->arguments().first()->type();
+ QVERIFY(unsignedShortType);
+ QCOMPARE(unsignedShortType->cppSignature(), QLatin1String("unsigned short"));
+ QVERIFY(unsignedShortType->isPrimitive());
+ QVERIFY(unsignedShortType->typeEntry()->isCppPrimitive());
+
+ const AbstractMetaType* ushortType = funcUShort->arguments().first()->type();
+ QVERIFY(ushortType);
+ QCOMPARE(ushortType->cppSignature(), QLatin1String("ushort"));
+ QVERIFY(ushortType->isPrimitive());
+ QVERIFY(ushortType->typeEntry()->isCppPrimitive());
+}
+
+QTEST_APPLESS_MAIN(TestNumericalTypedef)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.h b/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.h
new file mode 100644
index 000000000..e8af1fa8e
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testnumericaltypedef.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTNUMERICALTYPEDEF_H
+#define TESTNUMERICALTYPEDEF_H
+
+#include <QObject>
+
+class TestNumericalTypedef : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testNumericalTypedef();
+ void testUnsignedNumericalTypedef();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.cpp b/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.cpp
new file mode 100644
index 000000000..7646dd23a
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.cpp
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testprimitivetypetag.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestPrimitiveTypeTag::testPrimitiveTypeDefaultConstructor()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ struct B {};\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='A' default-constructor='A()'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+
+ PrimitiveTypeEntry* typeEntry = TypeDatabase::instance()->findPrimitiveType(QLatin1String("A"));
+ QVERIFY(typeEntry);
+ QVERIFY(typeEntry->hasDefaultConstructor());
+ QCOMPARE(typeEntry->defaultConstructor(), QLatin1String("A()"));
+}
+
+QTEST_APPLESS_MAIN(TestPrimitiveTypeTag)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.h b/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.h
new file mode 100644
index 000000000..ea9276de3
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testprimitivetypetag.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTPRIMITIVETYPETAG_H
+#define TESTPRIMITIVETYPETAG_H
+
+#include <QObject>
+
+class TestPrimitiveTypeTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testPrimitiveTypeDefaultConstructor();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp
new file mode 100644
index 000000000..e9f9f0ab7
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.cpp
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testrefcounttag.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestRefCountTag::testReferenceCountTag()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ struct B {\n\
+ void keepObject(B* b);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'>\n\
+ <modify-function signature='keepObject(B*)'>\n\
+ <modify-argument index='1'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ const AbstractMetaFunction* func = classB->findFunction(QLatin1String("keepObject"));
+ QVERIFY(func);
+ ReferenceCount refCount = func->modifications().first().argument_mods.first().referenceCounts.first();
+ QCOMPARE(refCount.action, ReferenceCount::Add);
+}
+
+void TestRefCountTag::testWithApiVersion()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ struct B {\n\
+ void keepObject(B*, B*);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'>\n\
+ <modify-function signature='keepObject(B*, B*)'>\n\
+ <modify-argument index='1' since='0.1'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ <modify-argument index='2' since='0.2'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false, "0.1"));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ const AbstractMetaFunction* func = classB->findFunction(QLatin1String("keepObject"));
+ QVERIFY(func);
+ ReferenceCount refCount = func->modifications().first().argument_mods.first().referenceCounts.first();
+ QCOMPARE(refCount.action, ReferenceCount::Add);
+
+ QCOMPARE(func->modifications().size(), 1);
+}
+
+
+QTEST_APPLESS_MAIN(TestRefCountTag)
+
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testrefcounttag.h b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.h
new file mode 100644
index 000000000..a95661293
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testrefcounttag.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTREFCOUNTTAG_H
+#define TESTREFCOUNTTAG_H
+
+#include <QObject>
+
+class TestRefCountTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testReferenceCountTag();
+ void testWithApiVersion();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.cpp b/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.cpp
new file mode 100644
index 000000000..f594cdd25
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.cpp
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testreferencetopointer.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestReferenceToPointer::testReferenceToPointerArgument()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ struct B {\n\
+ void dummy(A*&);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+ const AbstractMetaFunction* func = classB->findFunction(QLatin1String("dummy"));
+ QVERIFY(func);
+ QCOMPARE(func->arguments().first()->type()->minimalSignature(), QLatin1String("A*&"));
+}
+
+QTEST_APPLESS_MAIN(TestReferenceToPointer)
+
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.h b/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.h
new file mode 100644
index 000000000..83b0b6fad
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testreferencetopointer.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTREFERENCETOPOINTER_H
+#define TESTREFERENCETOPOINTER_H
+
+#include <QObject>
+
+class TestReferenceToPointer : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testReferenceToPointerArgument();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testremovefield.cpp b/sources/shiboken2/ApiExtractor/tests/testremovefield.cpp
new file mode 100644
index 000000000..7ebe49160
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testremovefield.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testremovefield.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestRemoveField::testRemoveField()
+{
+ const char* cppCode ="\
+ struct A {\n\
+ int fieldA;\n\
+ int fieldB;\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <modify-field name='fieldB' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->fields().size(), 1);
+ const AbstractMetaField* fieldA = classA->fields().first();
+ QVERIFY(fieldA);
+ QCOMPARE(fieldA->name(), QLatin1String("fieldA"));
+}
+
+QTEST_APPLESS_MAIN(TestRemoveField)
+
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testremovefield.h b/sources/shiboken2/ApiExtractor/tests/testremovefield.h
new file mode 100644
index 000000000..ea103e0cc
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testremovefield.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTREMOVEFIELD_H
+#define TESTREMOVEFIELD_H
+
+#include <QObject>
+
+class TestRemoveField : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testRemoveField();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.cpp b/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.cpp
new file mode 100644
index 000000000..a81380873
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testremoveimplconv.h"
+#include "testutil.h"
+#include <QtTest/QTest>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+// When a constructor able to trigger implicity conversions is removed
+// it should not appear in the implicity conversion list.
+void TestRemoveImplConv::testRemoveImplConv()
+{
+ const char* cppCode ="\
+ struct A {};\n\
+ struct B {};\n\
+ struct C {\n\
+ C(const A&);\n\
+ C(const B&);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'>\n\
+ <modify-function signature='C(const A&amp;)' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 3);
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+ const AbstractMetaClass *classC = AbstractMetaClass::findClass(classes, QLatin1String("C"));
+ QVERIFY(classC);
+ AbstractMetaFunctionList implConv = classC->implicitConversions();
+ QCOMPARE(implConv.count(), 1);
+ QCOMPARE(implConv.first()->arguments().first()->type()->typeEntry(), classB->typeEntry());
+}
+
+QTEST_APPLESS_MAIN(TestRemoveImplConv)
diff --git a/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.h b/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.h
new file mode 100644
index 000000000..62d5f74e6
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testremoveimplconv.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTREMOVEIMPLCONV_H
+#define TESTREMOVEIMPLCONV_H
+
+#include <QObject>
+
+class TestRemoveImplConv : public QObject
+{
+Q_OBJECT
+private slots:
+ void testRemoveImplConv();
+};
+
+#endif // TESTREMOVEIMPLCONV_H
diff --git a/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp
new file mode 100644
index 000000000..508cff586
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp
@@ -0,0 +1,117 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testremoveoperatormethod.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestRemoveOperatorMethod::testRemoveOperatorMethod()
+{
+ const char* cppCode ="\
+ #include <stdint.h>\n\
+ \n\
+ struct Char {};\n\
+ struct ByteArray {};\n\
+ struct String {};\n\
+ \n\
+ struct A {\n\
+ A& operator>>(char&);\n\
+ A& operator>>(char*);\n\
+ A& operator>>(short&);\n\
+ A& operator>>(unsigned short&);\n\
+ A& operator>>(int&);\n\
+ A& operator>>(unsigned int&);\n\
+ A& operator>>(int64_t&);\n\
+ A& operator>>(uint64_t&);\n\
+ A& operator>>(float&);\n\
+ A& operator>>(double&);\n\
+ A& operator>>(Char&);\n\
+ A& operator>>(ByteArray&);\n\
+ A& operator>>(String&);\n\
+ };\n";
+ const char* xmlCode = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='char'/>\n\
+ <primitive-type name='short'/>\n\
+ <primitive-type name='unsigned short'/>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='unsigned int'/>\n\
+ <primitive-type name='int64_t'/>\n\
+ <primitive-type name='uint64_t'/>\n\
+ <primitive-type name='float'/>\n\
+ <primitive-type name='double'/>\n\
+ <primitive-type name='Char'/>\n\
+ <primitive-type name='String'/>\n\
+ <value-type name='ByteArray'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='operator&gt;&gt;(char&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(char*)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(short&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(unsigned short&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(int&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(unsigned int&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(int64_t&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(uint64_t&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(float&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(double&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(Char&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(String&amp;)' remove='all'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 14);
+ QStringList removedSignatures;
+ removedSignatures.append(QLatin1String("operator>>(char&)"));
+ removedSignatures.append(QLatin1String("operator>>(char*)"));
+ removedSignatures.append(QLatin1String("operator>>(short&)"));
+ removedSignatures.append(QLatin1String("operator>>(unsigned short&)"));
+ removedSignatures.append(QLatin1String("operator>>(int&)"));
+ removedSignatures.append(QLatin1String("operator>>(unsigned int&)"));
+ removedSignatures.append(QLatin1String("operator>>(int64_t&)"));
+ removedSignatures.append(QLatin1String("operator>>(uint64_t&)"));
+ removedSignatures.append(QLatin1String("operator>>(float&)"));
+ removedSignatures.append(QLatin1String("operator>>(double&)"));
+ removedSignatures.append(QLatin1String("operator>>(Char&)"));
+ removedSignatures.append(QLatin1String("operator>>(String&)"));
+ int notRemoved = classA->functions().size();
+ const AbstractMetaFunctionList &functions = classA->functions();
+ for (const AbstractMetaFunction *f : functions) {
+ QCOMPARE(f->isModifiedRemoved(), bool(removedSignatures.contains(f->minimalSignature())));
+ notRemoved -= int(f->isModifiedRemoved());
+ }
+ QCOMPARE(notRemoved, 2);
+}
+
+QTEST_APPLESS_MAIN(TestRemoveOperatorMethod)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.h b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.h
new file mode 100644
index 000000000..17ff75d74
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTREMOVEOPERATORMETHOD_H
+#define TESTREMOVEOPERATORMETHOD_H
+
+#include <QObject>
+
+class TestRemoveOperatorMethod : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testRemoveOperatorMethod();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp b/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp
new file mode 100644
index 000000000..69691e860
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testresolvetype.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testresolvetype.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestResolveType::testResolveReturnTypeFromParentScope()
+{
+ const char* cppCode = "\n\
+ namespace A {\n\
+ struct B {\n\
+ struct C {};\n\
+ };\n\
+ struct D : public B::C {\n\
+ C* foo = 0;\n\
+ C* method();\n\
+ };\n\
+ };";
+ const char* xmlCode = "\n\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='A'/>\n\
+ <value-type name='A::B'/>\n\
+ <value-type name='A::B::C'/>\n\
+ <value-type name='A::D'/>\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classD = AbstractMetaClass::findClass(classes, QLatin1String("A::D"));
+ QVERIFY(classD);
+ const AbstractMetaFunction* meth = classD->findFunction(QLatin1String("method"));
+ QVERIFY(meth);
+}
+
+QTEST_APPLESS_MAIN(TestResolveType)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testresolvetype.h b/sources/shiboken2/ApiExtractor/tests/testresolvetype.h
new file mode 100644
index 000000000..6164d0074
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testresolvetype.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTRESOLVETYPE_H
+#define TESTRESOLVETYPE_H
+
+#include <QObject>
+
+class TestResolveType : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testResolveReturnTypeFromParentScope();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp
new file mode 100644
index 000000000..18d6902c2
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testreverseoperators.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestReverseOperators::testReverseSum()
+{
+ const char cppCode[] = "struct A {\n\
+ A& operator+(int);\n\
+ };\n\
+ A& operator+(int, const A&);";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' />\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClass* classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().count(), 4);
+
+ const AbstractMetaFunction* reverseOp = 0;
+ const AbstractMetaFunction* normalOp = 0;
+ for (const AbstractMetaFunction *func : classA->functions()) {
+ if (func->name() == QLatin1String("operator+")) {
+ if (func->isReverseOperator())
+ reverseOp = func;
+ else
+ normalOp = func;
+ }
+ }
+
+ QVERIFY(normalOp);
+ QVERIFY(!normalOp->isReverseOperator());
+ QCOMPARE(normalOp->arguments().count(), 1);
+ QVERIFY(reverseOp);
+ QVERIFY(reverseOp->isReverseOperator());
+ QCOMPARE(reverseOp->arguments().count(), 1);
+}
+
+void TestReverseOperators::testReverseSumWithAmbiguity()
+{
+ const char cppCode[] = "\n\
+ struct A { A operator+(int); };\n\
+ A operator+(int, const A&);\n\
+ struct B {};\n\
+ B operator+(const A&, const B&);\n\
+ B operator+(const B&, const A&);\n\
+ int operator-(int, const A*);\n\
+ int operator/(const A*, int);\n\
+ ";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' />\n\
+ <value-type name='B' />\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QEXPECT_FAIL("", "Clang: Does not compile", Abort);
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().count(), 6);
+
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+ QCOMPARE(classB->functions().count(), 4);
+
+ const AbstractMetaFunction* reverseOp = 0;
+ const AbstractMetaFunction* normalOp = 0;
+ for (const AbstractMetaFunction *func : classB->functions()) {
+ if (func->name() == QLatin1String("operator+")) {
+ if (func->isReverseOperator())
+ reverseOp = func;
+ else
+ normalOp = func;
+ }
+ }
+ QVERIFY(normalOp);
+ QVERIFY(!normalOp->isReverseOperator());
+ QCOMPARE(normalOp->arguments().count(), 1);
+ QCOMPARE(normalOp->minimalSignature(), QLatin1String("operator+(B,A)"));
+ QVERIFY(reverseOp);
+ QVERIFY(reverseOp->isReverseOperator());
+ QCOMPARE(reverseOp->arguments().count(), 1);
+ QCOMPARE(reverseOp->minimalSignature(), QLatin1String("operator+(A,B)"));
+
+ reverseOp = classA->findFunction(QLatin1String("operator-"));
+ QVERIFY(reverseOp);
+ QCOMPARE(reverseOp->arguments().count(), 1);
+ QVERIFY(reverseOp->isPointerOperator());
+ QVERIFY(reverseOp->isReverseOperator());
+
+ normalOp = classA->findFunction(QLatin1String("operator/"));
+ QVERIFY(normalOp);
+ QCOMPARE(normalOp->arguments().count(), 1);
+ QVERIFY(normalOp->isPointerOperator());
+ QVERIFY(!normalOp->isReverseOperator());
+
+}
+
+
+
+QTEST_APPLESS_MAIN(TestReverseOperators)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testreverseoperators.h b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.h
new file mode 100644
index 000000000..3bd65fb85
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTREVERSEOPERATORS_H
+#define TESTREVERSEOPERATORS_H
+#include <QObject>
+
+class TestReverseOperators : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testReverseSum();
+ void testReverseSumWithAmbiguity();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
new file mode 100644
index 000000000..4a66264d8
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp
@@ -0,0 +1,439 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testtemplates.h"
+#include <QtTest/QTest>
+#include <QTemporaryFile>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestTemplates::testTemplateWithNamespace()
+{
+ const char cppCode[] = "\n\
+ template<typename T> struct QList {}; \n\
+ struct Url {\n\
+ void name();\n\
+ };\n\
+ namespace Internet {\n\
+ struct Url{};\n\
+ struct Bookmarks {\n\
+ QList<Url> list();\n\
+ };\n\
+ }";
+ const char xmlCode0[] = "\n\
+ <typesystem package='Pakcage.Network'>\n\
+ <value-type name='Url'/>\n\
+ </typesystem>";
+
+ QTemporaryFile file;
+ QVERIFY(file.open());
+ file.write(xmlCode0);
+ file.close();
+
+ QString xmlCode1 = QString::fromLatin1("\n\
+ <typesystem package='Package.Internet'>\n\
+ <load-typesystem name='%1' generate='no'/>\n\
+ <container-type name='QList' type='list'/>\n\
+ <namespace-type name='Internet' generate='no'/>\n\
+ <value-type name='Internet::Url'/>\n\
+ <value-type name='Internet::Bookmarks'/>\n\
+ </typesystem>").arg(file.fileName());
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+
+ AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Bookmarks"));
+ QVERIFY(classB);
+ const AbstractMetaFunction* func = classB->findFunction(QLatin1String("list"));
+ AbstractMetaType* funcType = func->type();
+ QVERIFY(funcType);
+ QCOMPARE(funcType->cppSignature(), QLatin1String("QList<Internet::Url >"));
+}
+
+void TestTemplates::testTemplateOnContainers()
+{
+ const char cppCode[] = "\n\
+ struct Base {};\n\
+ template<typename T> struct QList {}; \n\
+ namespace Namespace {\n\
+ enum SomeEnum { E1, E2 };\n\
+ template<SomeEnum type> struct A {\n\
+ A<type> foo(const QList<A<type> >& a);\n\
+ };\n\
+ typedef A<E1> B;\n\
+ }\n\
+ ";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Package\">\n\
+ <container-type name='QList' type='list'/>\n\
+ <namespace-type name='Namespace'/>\n\
+ <enum-type name='Namespace::SomeEnum'/>\n\
+ <object-type name='Base'/>\n\
+ <object-type name='Namespace::A' generate='no'/>\n\
+ <object-type name='Namespace::B'/>\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+
+ AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isNull());
+ const AbstractMetaFunction* func = classB->findFunction(QLatin1String("foo"));
+ AbstractMetaType* argType = func->arguments().first()->type();
+ QCOMPARE(argType->instantiations().count(), 1);
+ QCOMPARE(argType->typeEntry()->qualifiedCppName(), QLatin1String("QList"));
+
+ const AbstractMetaType* instance1 = argType->instantiations().first();
+ QCOMPARE(instance1->instantiations().count(), 1);
+ QCOMPARE(instance1->typeEntry()->qualifiedCppName(), QLatin1String("Namespace::A"));
+
+ const AbstractMetaType* instance2 = instance1->instantiations().first();
+ QCOMPARE(instance2->instantiations().count(), 0);
+ QCOMPARE(instance2->typeEntry()->qualifiedCppName(), QLatin1String("Namespace::E1"));
+}
+
+void TestTemplates::testTemplateValueAsArgument()
+{
+ const char cppCode[] = "\n\
+ template<typename T> struct List {};\n\
+ void func(List<int> arg) {}\n\
+ ";
+
+ const char xmlCode[] = "\n\
+ <typesystem package='Package'>\n\
+ <primitive-type name='int'/>\n\
+ <container-type name='List' type='list'/>\n\
+ <function signature='func(List&lt;int&gt;)'/>\n\
+ </typesystem>\n\
+ ";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaFunctionList globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.count(), 1);
+
+ AbstractMetaFunction* func = globalFuncs.first();
+ QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>)"));
+ QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List<int >"));
+}
+
+void TestTemplates::testTemplatePointerAsArgument()
+{
+ const char cppCode[] = "\n\
+ template<typename T> struct List {};\n\
+ void func(List<int>* arg) {}\n\
+ ";
+
+ const char xmlCode[] = "\n\
+ <typesystem package='Package'>\n\
+ <primitive-type name='int'/>\n\
+ <container-type name='List' type='list'/>\n\
+ <function signature='func(List&lt;int&gt;*)'/>\n\
+ </typesystem>\n\
+ ";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaFunctionList globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.count(), 1);
+
+ AbstractMetaFunction* func = globalFuncs.first();
+ QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>*)"));
+ QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List<int > *"));
+}
+
+void TestTemplates::testTemplateReferenceAsArgument()
+{
+ const char cppCode[] = "\n\
+ template<typename T> struct List {};\n\
+ void func(List<int>& arg) {}\n\
+ ";
+
+ const char xmlCode[] = "\n\
+ <typesystem package='Package'>\n\
+ <primitive-type name='int'/>\n\
+ <container-type name='List' type='list'/>\n\
+ <function signature='func(List&lt;int&gt;&amp;)'/>\n\
+ </typesystem>\n\
+ ";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaFunctionList globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.count(), 1);
+
+ AbstractMetaFunction* func = globalFuncs.first();
+ QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>&)"));
+ QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List<int > &"));
+}
+
+void TestTemplates::testTemplateParameterFixup()
+{
+ const char cppCode[] = "\n\
+ template<typename T>\n\
+ struct List {\n\
+ struct Iterator {};\n\
+ void append(List l);\n\
+ void erase(List::Iterator it);\n\
+ };\n";
+
+ const char xmlCode[] = "\n\
+ <typesystem package='Package'>\n\
+ <container-type name='List' type='list'/>\n\
+ <value-type name='List::Iterator'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ const AbstractMetaClassList templates = builder->templates();
+
+ QCOMPARE(templates.count(), 1);
+ const AbstractMetaClass *list = templates.first();
+ // Verify that the parameter of "void append(List l)" gets fixed to "List<T >"
+ const AbstractMetaFunction *append = list->findFunction(QStringLiteral("append"));
+ QVERIFY(append);
+ QCOMPARE(append->arguments().size(), 1);
+ QCOMPARE(append->arguments().at(0)->type()->cppSignature(), QLatin1String("List<T >"));
+ // Verify that the parameter of "void erase(Iterator)" is not modified
+ const AbstractMetaFunction *erase = list->findFunction(QStringLiteral("erase"));
+ QVERIFY(erase);
+ QCOMPARE(erase->arguments().size(), 1);
+ QEXPECT_FAIL("", "Clang: Some other code changes the parameter type", Abort);
+ QCOMPARE(erase->arguments().at(0)->type()->cppSignature(), QLatin1String("List::Iterator"));
+}
+
+void TestTemplates::testInheritanceFromContainterTemplate()
+{
+ const char cppCode[] = "\n\
+ template<typename T>\n\
+ struct ListContainer {\n\
+ inline void push_front(const T& t);\n\
+ inline T& front();\n\
+ };\n\
+ struct FooBar {};\n\
+ struct FooBars : public ListContainer<FooBar> {};\n\
+ ";
+
+ const char xmlCode[] = "\n\
+ <typesystem package='Package'>\n\
+ <container-type name='ListContainer' type='list'/>\n\
+ <value-type name='FooBar'/>\n\
+ <value-type name='FooBars'>\n\
+ <modify-function signature='push_front(FooBar)' remove='all'/>\n\
+ <modify-function signature='front()' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n\
+ ";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClassList templates = builder->templates();
+ QCOMPARE(classes.count(), 2);
+ QCOMPARE(templates.count(), 1);
+
+ const AbstractMetaClass* foobars = AbstractMetaClass::findClass(classes, QLatin1String("FooBars"));
+ QCOMPARE(foobars->functions().count(), 4);
+
+ const AbstractMetaClass* lc = templates.first();
+ QCOMPARE(lc->functions().count(), 2);
+}
+
+void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration()
+{
+ const char cppCode[] = "\n\
+ enum SomeEnum { E1, E2 };\n\
+ template<SomeEnum type> struct Future;\n\
+ template<SomeEnum type>\n\
+ struct A {\n\
+ A();\n\
+ void method();\n\
+ friend struct Future<type>;\n\
+ };\n\
+ typedef A<E1> B;\n\
+ template<SomeEnum type> struct Future {};\n\
+ ";
+ const char xmlCode[] = "\n\
+ <typesystem package='Package'>\n\
+ <enum-type name='SomeEnum'/>\n\
+ <value-type name='A' generate='no'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='Future' generate='no'/>\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+
+ AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isNull());
+ // 3 functions: simple constructor, copy constructor and "method()".
+ QCOMPARE(classB->functions().count(), 3);
+}
+
+void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration()
+{
+ const char cppCode[] = "\n\
+ namespace Namespace {\n\
+ enum SomeEnum { E1, E2 };\n\
+ template<SomeEnum type> struct Future;\n\
+ template<SomeEnum type>\n\
+ struct A {\n\
+ A();\n\
+ void method();\n\
+ friend struct Future<type>;\n\
+ };\n\
+ typedef A<E1> B;\n\
+ template<SomeEnum type> struct Future {};\n\
+ };\n\
+ ";
+ const char xmlCode[] = "\n\
+ <typesystem package='Package'>\n\
+ <namespace-type name='Namespace'/>\n\
+ <enum-type name='Namespace::SomeEnum'/>\n\
+ <value-type name='Namespace::A' generate='no'/>\n\
+ <value-type name='Namespace::B'/>\n\
+ <value-type name='Namespace::Future' generate='no'/>\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+
+ AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Namespace::B"));
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isNull());
+ // 3 functions: simple constructor, copy constructor and "method()".
+ QCOMPARE(classB->functions().count(), 3);
+}
+
+void TestTemplates::testTypedefOfInstantiationOfTemplateClass()
+{
+ const char cppCode[] = "\n\
+ namespace NSpace {\n\
+ enum ClassType {\n\
+ TypeOne\n\
+ };\n\
+ template<ClassType CLASS_TYPE>\n\
+ struct BaseTemplateClass {\n\
+ inline ClassType getClassType() const { CLASS_TYPE; }\n\
+ };\n\
+ typedef BaseTemplateClass<TypeOne> TypeOneClass;\n\
+ }\n\
+ ";
+
+ const char xmlCode[] = "\n\
+ <typesystem package='Package'>\n\
+ <namespace-type name='NSpace'>\n\
+ <enum-type name='ClassType'/>\n\
+ <object-type name='BaseTemplateClass' generate='no'/>\n\
+ <object-type name='TypeOneClass'/>\n\
+ </namespace-type>\n\
+ </typesystem>\n\
+ ";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 3);
+
+ const AbstractMetaClass* base = AbstractMetaClass::findClass(classes, QLatin1String("BaseTemplateClass"));
+ QVERIFY(base);
+ const AbstractMetaClass* one = AbstractMetaClass::findClass(classes, QLatin1String("TypeOneClass"));
+ QVERIFY(one);
+ QCOMPARE(one->templateBaseClass(), base);
+ QCOMPARE(one->functions().count(), base->functions().count());
+ QVERIFY(one->isTypeDef());
+ const ComplexTypeEntry* oneType = one->typeEntry();
+ const ComplexTypeEntry* baseType = base->typeEntry();
+ QCOMPARE(oneType->baseContainerType(), baseType);
+ QCOMPARE(one->baseClassNames(), QStringList(QLatin1String("BaseTemplateClass<TypeOne>")));
+
+ QVERIFY(one->hasTemplateBaseClassInstantiations());
+ AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations();
+ QCOMPARE(instantiations.count(), 1);
+ const AbstractMetaType* inst = instantiations.first();
+ QVERIFY(inst);
+ QVERIFY(!inst->isEnum());
+ QVERIFY(!inst->typeEntry()->isEnum());
+ QVERIFY(inst->typeEntry()->isEnumValue());
+ QCOMPARE(inst->cppSignature(), QLatin1String("NSpace::TypeOne"));
+}
+
+void TestTemplates::testContainerTypeIncompleteArgument()
+{
+ const char* cppCode ="\n\
+ template<typename T>\n\
+ class Vector {\n\
+ void method(const Vector& vector);\n\
+ Vector otherMethod();\n\
+ };\n\
+ template <typename T>\n\
+ void Vector<T>::method(const Vector<T>& vector) {}\n\
+ template <typename T>\n\
+ Vector<T> Vector<T>::otherMethod() { return Vector<T>(); }\n\
+ typedef Vector<int> IntVector;\n\
+ ";
+ const char* xmlCode = "\n\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <container-type name='Vector' type='vector'/>\n\
+ <value-type name='IntVector'/>\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.count(), 1);
+
+ AbstractMetaClass* vector = AbstractMetaClass::findClass(classes, QLatin1String("IntVector"));
+ QVERIFY(vector);
+ QVERIFY(vector->typeEntry()->baseContainerType());
+ QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(vector->typeEntry()->baseContainerType())->type(), ContainerTypeEntry::VectorContainer);
+ QCOMPARE(vector->functions().count(), 4);
+
+ const AbstractMetaFunction* method = vector->findFunction(QLatin1String("method"));
+ QVERIFY(method);
+ QCOMPARE(method->signature(), QLatin1String("method(const Vector<int > & vector)"));
+
+ const AbstractMetaFunction* otherMethod = vector->findFunction(QLatin1String("otherMethod"));
+ QVERIFY(otherMethod);
+ QCOMPARE(otherMethod->signature(), QLatin1String("otherMethod()"));
+ QVERIFY(otherMethod->type());
+ QCOMPARE(otherMethod->type()->cppSignature(), QLatin1String("Vector<int >"));
+}
+
+QTEST_APPLESS_MAIN(TestTemplates)
diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.h b/sources/shiboken2/ApiExtractor/tests/testtemplates.h
new file mode 100644
index 000000000..7b0d0f3b3
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.h
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTTEMPLATES_H
+#define TESTTEMPLATES_H
+
+#include <QObject>
+
+class TestTemplates : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testTemplateOnContainers();
+ void testTemplateWithNamespace();
+ void testTemplateValueAsArgument();
+ void testTemplatePointerAsArgument();
+ void testTemplateReferenceAsArgument();
+ void testTemplateParameterFixup();
+ void testInheritanceFromContainterTemplate();
+ void testTemplateInheritanceMixedWithForwardDeclaration();
+ void testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration();
+ void testTypedefOfInstantiationOfTemplateClass();
+ void testContainerTypeIncompleteArgument();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testtoposort.cpp b/sources/shiboken2/ApiExtractor/tests/testtoposort.cpp
new file mode 100644
index 000000000..30d368a8a
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testtoposort.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testtoposort.h"
+#include <QtTest/QTest>
+#include "graph.h"
+#include <QDebug>
+
+void TestTopoSort::testTopoSort()
+{
+ QLinkedList<int> result;
+ {
+ Graph g(3);
+ g.addEdge(1, 2);
+ g.addEdge(0, 1);
+ result = g.topologicalSort();
+ QCOMPARE(result.size(), 3);
+ QLinkedList<int>::iterator it = result.begin();
+ QCOMPARE(*it, 0);
+ QCOMPARE(*(++it), 1);
+ QCOMPARE(*(++it), 2);
+ }
+ {
+ Graph g(2);
+ result = g.topologicalSort();
+ QCOMPARE(result.size(), 2);
+ QLinkedList<int>::iterator it = result.begin();
+ QCOMPARE(*it, 1);
+ QCOMPARE(*(++it), 0);
+ }
+}
+
+void TestTopoSort::testCiclicGraph()
+{
+ Graph g(3);
+ g.addEdge(0, 1);
+ g.addEdge(1, 2);
+ g.addEdge(2, 0);
+ QLinkedList<int> result = g.topologicalSort();
+ QVERIFY(result.isEmpty());
+}
+
+QTEST_APPLESS_MAIN(TestTopoSort)
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testtoposort.h b/sources/shiboken2/ApiExtractor/tests/testtoposort.h
new file mode 100644
index 000000000..ae8a2bab8
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testtoposort.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTTOPOSORT_H
+#define TESTTOPOSORT_H
+
+#include <QObject>
+
+class TestTopoSort : public QObject
+{
+Q_OBJECT
+private slots:
+ void testTopoSort();
+ void testCiclicGraph();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp
new file mode 100644
index 000000000..804683140
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testtyperevision.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestTypeRevision::testRevisionAttr()
+{
+ const char* cppCode = "class Rev_0 {};"
+ "class Rev_1 {};"
+ "class Rev_2 { public: enum Rev_3 { X }; enum Rev_5 { Y }; };";
+ const char* xmlCode = "<typesystem package=\"Foo\">"
+ "<value-type name=\"Rev_0\"/>"
+ "<value-type name=\"Rev_1\" revision=\"1\"/>"
+ "<object-type name=\"Rev_2\" revision=\"2\">"
+ " <enum-type name=\"Rev_3\" revision=\"3\" flags=\"Flag_4\" flags-revision=\"4\" />"
+ " <enum-type name=\"Rev_5\" revision=\"5\" flags=\"Flag_5\" />"
+ "</object-type>"
+ "</typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *rev0 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_0"));
+ QCOMPARE(getTypeRevision(rev0->typeEntry()), 0);
+
+ const AbstractMetaClass *rev1 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_1"));
+ QCOMPARE(getTypeRevision(rev1->typeEntry()), 1);
+
+ AbstractMetaClass *rev2 = AbstractMetaClass::findClass(classes, QLatin1String("Rev_2"));
+ QCOMPARE(getTypeRevision(rev2->typeEntry()), 2);
+
+ AbstractMetaEnum* rev3 = rev2->findEnum(QLatin1String("Rev_3"));
+ QCOMPARE(getTypeRevision(rev3->typeEntry()), 3);
+ FlagsTypeEntry* rev4 = rev3->typeEntry()->flags();
+ QCOMPARE(getTypeRevision(rev4), 4);
+ AbstractMetaEnum* rev5 = rev2->findEnum(QLatin1String("Rev_5"));
+ QCOMPARE(getTypeRevision(rev5->typeEntry()), 5);
+ QCOMPARE(getTypeRevision(rev5->typeEntry()->flags()), 5);
+}
+
+QTEST_APPLESS_MAIN(TestTypeRevision)
+
+
diff --git a/sources/shiboken2/ApiExtractor/tests/testtyperevision.h b/sources/shiboken2/ApiExtractor/tests/testtyperevision.h
new file mode 100644
index 000000000..dcb2d8794
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testtyperevision.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTTYPEREVISION_H
+#define TESTTYPEREVISION_H
+
+#include <QObject>
+
+class TestTypeRevision : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testRevisionAttr();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testutil.h b/sources/shiboken2/ApiExtractor/tests/testutil.h
new file mode 100644
index 000000000..200fdb104
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testutil.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTUTIL_H
+#define TESTUTIL_H
+#include <QtCore/QBuffer>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QTemporaryFile>
+#include "abstractmetabuilder.h"
+#include "reporthandler.h"
+#include "typedatabase.h"
+
+namespace TestUtil
+{
+ static AbstractMetaBuilder *parse(const char *cppCode, const char *xmlCode,
+ bool silent = true,
+ const char *apiVersion = Q_NULLPTR,
+ const QStringList &dropTypeEntries = QStringList())
+ {
+ ReportHandler::setSilent(silent);
+ TypeDatabase* td = TypeDatabase::instance(true);
+ if (apiVersion && !td->setApiVersion(QLatin1String("*"), QLatin1String(apiVersion)))
+ return Q_NULLPTR;
+ td->setDropTypeEntries(dropTypeEntries);
+ QBuffer buffer;
+ // parse typesystem
+ buffer.setData(xmlCode);
+ if (!buffer.open(QIODevice::ReadOnly))
+ return Q_NULLPTR;
+ td->parseFile(&buffer);
+ buffer.close();
+ // parse C++ code
+ QTemporaryFile tempSource(QDir::tempPath() + QLatin1String("/st_XXXXXX_main.cpp"));
+ if (!tempSource.open()) {
+ qWarning().noquote().nospace() << "Creation of temporary file failed: "
+ << tempSource.errorString();
+ return nullptr;
+ }
+ QByteArrayList arguments;
+ arguments.append(QFile::encodeName(tempSource.fileName()));
+ tempSource.write(cppCode, qint64(strlen(cppCode)));
+ tempSource.close();
+ AbstractMetaBuilder *builder = new AbstractMetaBuilder;
+ if (!builder->build(arguments, 0)) {
+ delete builder;
+ return Q_NULLPTR;
+ }
+ return builder;
+ }
+} // namespace TestUtil
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.cpp b/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.cpp
new file mode 100644
index 000000000..627255d37
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testvaluetypedefaultctortag.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestValueTypeDefaultCtorTag::testValueTypeDefaultCtorTagArgument()
+{
+ const char* cppCode ="\n\
+ struct A {\n\
+ A(int,int);\n\
+ };\n\
+ struct B {};\n\
+ ";
+ const char* xmlCode = "\n\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' default-constructor='A(0, 0)' />\n\
+ <value-type name='B' />\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+
+ AbstractMetaClassList classes = builder->classes();
+
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ QVERIFY(classA->typeEntry()->hasDefaultConstructor());
+ QCOMPARE(classA->typeEntry()->defaultConstructor(), QLatin1String("A(0, 0)"));
+
+ const AbstractMetaClass *classB = AbstractMetaClass::findClass(classes, QLatin1String("B"));
+ QVERIFY(classB);
+ QVERIFY(!classB->typeEntry()->hasDefaultConstructor());
+}
+
+QTEST_APPLESS_MAIN(TestValueTypeDefaultCtorTag)
diff --git a/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.h b/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.h
new file mode 100644
index 000000000..2d2efe79d
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testvaluetypedefaultctortag.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTVALUETYPEDEFAULTCTORTAG_H
+#define TESTVALUETYPEDEFAULTCTORTAG_H
+
+#include <QObject>
+
+class TestValueTypeDefaultCtorTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testValueTypeDefaultCtorTagArgument();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/testvoidarg.cpp b/sources/shiboken2/ApiExtractor/tests/testvoidarg.cpp
new file mode 100644
index 000000000..5f0b47389
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testvoidarg.cpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "testvoidarg.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestVoidArg::testVoidParsedFunction()
+{
+ const char cppCode[] = "struct A { void a(void); };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("a"));
+ QCOMPARE(addedFunc->arguments().count(), 0);
+}
+
+void TestVoidArg::testVoidAddedFunction()
+{
+ const char cppCode[] = "struct A { };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' >\n\
+ <add-function signature=\"a(void)\"/>\n\
+ </value-type>\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("a"));
+ QCOMPARE(addedFunc->arguments().count(), 0);
+
+}
+
+void TestVoidArg::testVoidPointerParsedFunction()
+{
+ const char cppCode[] = "struct A { void a(void*); };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassList classes = builder->classes();
+ const AbstractMetaClass *classA = AbstractMetaClass::findClass(classes, QLatin1String("A"));
+ QVERIFY(classA);
+ const AbstractMetaFunction* addedFunc = classA->findFunction(QLatin1String("a"));
+ QCOMPARE(addedFunc->arguments().count(), 1);
+
+}
+
+QTEST_APPLESS_MAIN(TestVoidArg)
diff --git a/sources/shiboken2/ApiExtractor/tests/testvoidarg.h b/sources/shiboken2/ApiExtractor/tests/testvoidarg.h
new file mode 100644
index 000000000..40d96a4ff
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/testvoidarg.h
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TESTVOIDARG_H
+#define TESTVOIDARG_H
+#include <QObject>
+
+class TestVoidArg : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testVoidParsedFunction();
+ void testVoidPointerParsedFunction();
+ void testVoidAddedFunction();
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/tests/utf8code.txt b/sources/shiboken2/ApiExtractor/tests/utf8code.txt
new file mode 100644
index 000000000..6d5fa9dcf
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/tests/utf8code.txt
@@ -0,0 +1 @@
+áéíóú \ No newline at end of file
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.cpp b/sources/shiboken2/ApiExtractor/typedatabase.cpp
new file mode 100644
index 000000000..a1b28070b
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp
@@ -0,0 +1,745 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "typedatabase.h"
+#include "typesystem.h"
+#include "typesystem_p.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QPair>
+#include <QtCore/QVector>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QVersionNumber>
+#include <QtCore/QXmlStreamReader>
+#include "reporthandler.h"
+// #include <tr1/tuple>
+#include <algorithm>
+
+// package -> api-version
+
+static QString wildcardToRegExp(QString w)
+{
+ w.replace(QLatin1Char('?'), QLatin1Char('.'));
+ w.replace(QLatin1Char('*'), QStringLiteral(".*"));
+ return w;
+}
+
+typedef QPair<QRegularExpression, QVersionNumber> ApiVersion;
+typedef QVector<ApiVersion> ApiVersions;
+
+Q_GLOBAL_STATIC(ApiVersions, apiVersions)
+
+TypeDatabase::TypeDatabase() : m_suppressWarnings(true)
+{
+ addType(new VoidTypeEntry());
+ addType(new VarargsTypeEntry());
+}
+
+TypeDatabase::~TypeDatabase()
+{
+}
+
+TypeDatabase* TypeDatabase::instance(bool newInstance)
+{
+ static TypeDatabase* db = 0;
+ if (!db || newInstance) {
+ if (db)
+ delete db;
+ db = new TypeDatabase;
+ }
+ return db;
+}
+
+// A list of regex/replacements to fix int types like "ushort" to "unsigned short"
+// unless present in TypeDatabase
+struct IntTypeNormalizationEntry
+{
+ QRegularExpression regex;
+ QString replacement;
+};
+
+typedef QVector<IntTypeNormalizationEntry> IntTypeNormalizationEntries;
+
+static const IntTypeNormalizationEntries &intTypeNormalizationEntries()
+{
+ static IntTypeNormalizationEntries result;
+ static bool firstTime = true;
+ if (firstTime) {
+ firstTime = false;
+ static const char *intTypes[] = {"char", "short", "int", "long"};
+ const size_t size = sizeof(intTypes) / sizeof(intTypes[0]);
+ for (size_t i = 0; i < size; ++i) {
+ const QString intType = QLatin1String(intTypes[i]);
+ if (!TypeDatabase::instance()->findType(QLatin1Char('u') + intType)) {
+ IntTypeNormalizationEntry entry;
+ entry.replacement = QStringLiteral("unsigned ") + intType;
+ entry.regex.setPattern(QStringLiteral("\\bu") + intType + QStringLiteral("\\b"));
+ Q_ASSERT(entry.regex.isValid());
+ result.append(entry);
+ }
+ }
+ }
+ return result;
+}
+
+QString TypeDatabase::normalizedSignature(const QString &signature)
+{
+ QString normalized = QLatin1String(QMetaObject::normalizedSignature(signature.toUtf8().constData()));
+
+ if (instance() && signature.contains(QLatin1String("unsigned"))) {
+ const IntTypeNormalizationEntries &entries = intTypeNormalizationEntries();
+ for (int i = 0, size = entries.size(); i < size; ++i)
+ normalized.replace(entries.at(i).regex, entries.at(i).replacement);
+ }
+
+ return normalized;
+}
+
+QStringList TypeDatabase::requiredTargetImports() const
+{
+ return m_requiredTargetImports;
+}
+
+void TypeDatabase::addRequiredTargetImport(const QString& moduleName)
+{
+ if (!m_requiredTargetImports.contains(moduleName))
+ m_requiredTargetImports << moduleName;
+}
+
+void TypeDatabase::addTypesystemPath(const QString& typesystem_paths)
+{
+ #if defined(Q_OS_WIN32)
+ const char path_splitter = ';';
+ #else
+ const char path_splitter = ':';
+ #endif
+ m_typesystemPaths += typesystem_paths.split(QLatin1Char(path_splitter));
+}
+
+IncludeList TypeDatabase::extraIncludes(const QString& className) const
+{
+ ComplexTypeEntry* typeEntry = findComplexType(className);
+ if (typeEntry)
+ return typeEntry->extraIncludes();
+ else
+ return IncludeList();
+}
+
+ContainerTypeEntry* TypeDatabase::findContainerType(const QString &name) const
+{
+ QString template_name = name;
+
+ int pos = name.indexOf(QLatin1Char('<'));
+ if (pos > 0)
+ template_name = name.left(pos);
+
+ TypeEntry* type_entry = findType(template_name);
+ if (type_entry && type_entry->isContainer())
+ return static_cast<ContainerTypeEntry*>(type_entry);
+ return 0;
+}
+
+FunctionTypeEntry* TypeDatabase::findFunctionType(const QString& name) const
+{
+ TypeEntry* entry = findType(name);
+ if (entry && entry->type() == TypeEntry::FunctionType)
+ return static_cast<FunctionTypeEntry*>(entry);
+ return 0;
+}
+
+TypeEntry* TypeDatabase::findType(const QString& name) const
+{
+ const TypeEntryList &entries = findTypes(name);
+ for (TypeEntry *entry : entries) {
+ if (entry &&
+ (!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) {
+ return entry;
+ }
+ }
+ return 0;
+}
+
+TypeEntryList TypeDatabase::findTypes(const QString &name) const
+{
+ return m_entries.value(name);
+}
+
+SingleTypeEntryHash TypeDatabase::entries() const
+{
+ TypeEntryHash entries = allEntries();
+
+ SingleTypeEntryHash returned;
+ for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it)
+ returned.insert(it.key(), findType(it.key()));
+
+ return returned;
+}
+
+PrimitiveTypeEntryList TypeDatabase::primitiveTypes() const
+{
+ TypeEntryHash entries = allEntries();
+ PrimitiveTypeEntryList returned;
+ for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
+ for (TypeEntry *typeEntry : it.value()) {
+ if (typeEntry->isPrimitive())
+ returned.append(static_cast<PrimitiveTypeEntry *>(typeEntry));
+ }
+ }
+ return returned;
+}
+
+ContainerTypeEntryList TypeDatabase::containerTypes() const
+{
+ TypeEntryHash entries = allEntries();
+ ContainerTypeEntryList returned;
+ for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) {
+ for (TypeEntry *typeEntry : it.value()) {
+ if (typeEntry->isContainer())
+ returned.append(static_cast<ContainerTypeEntry *>(typeEntry));
+ }
+ }
+ return returned;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeRejection &r)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "TypeRejection(type=" << r.matchType << ", class="
+ << r.className.pattern() << ", pattern=" << r.pattern.pattern() << ')';
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+void TypeDatabase::addRejection(const TypeRejection &r)
+{
+ m_rejections << r;
+}
+
+static inline QString msgRejectReason(const TypeRejection &r, const QString &needle = QString())
+{
+ QString result;
+ QTextStream str(&result);
+ switch (r.matchType) {
+ case TypeRejection::ExcludeClass:
+ str << " matches class exclusion \"" << r.className.pattern() << '"';
+ break;
+ case TypeRejection::Function:
+ case TypeRejection::Field:
+ case TypeRejection::Enum:
+ str << " matches class \"" << r.className.pattern() << "\" and \"" << r.pattern.pattern() << '"';
+ break;
+ case TypeRejection::ArgumentType:
+ case TypeRejection::ReturnType:
+ str << " matches class \"" << r.className.pattern() << "\" and \"" << needle
+ << "\" matches \"" << r.pattern.pattern() << '"';
+ break;
+ }
+ return result;
+}
+
+// Match class name only
+bool TypeDatabase::isClassRejected(const QString& className, QString *reason) const
+{
+ for (const TypeRejection& r : m_rejections) {
+ if (r.matchType == TypeRejection::ExcludeClass && r.className.match(className).hasMatch()) {
+ if (reason)
+ *reason = msgRejectReason(r);
+ return true;
+ }
+ }
+ return false;
+}
+
+// Match class name and function/enum/field
+static bool findRejection(const QVector<TypeRejection> &rejections,
+ TypeRejection::MatchType matchType,
+ const QString& className, const QString& name,
+ QString *reason = nullptr)
+{
+ Q_ASSERT(matchType != TypeRejection::ExcludeClass);
+ for (const TypeRejection& r : rejections) {
+ if (r.matchType == matchType && r.pattern.match(name).hasMatch()
+ && r.className.match(className).hasMatch()) {
+ if (reason)
+ *reason = msgRejectReason(r, name);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumName, QString *reason) const
+{
+ return findRejection(m_rejections, TypeRejection::Enum, className, enumName, reason);
+}
+
+void TypeDatabase::addType(TypeEntry *e)
+{
+ m_entries[e->qualifiedCppName()].append(e);
+}
+
+bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName,
+ QString *reason) const
+{
+ return findRejection(m_rejections, TypeRejection::Function, className, functionName, reason);
+}
+
+bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName,
+ QString *reason) const
+{
+ return findRejection(m_rejections, TypeRejection::Field, className, fieldName, reason);
+}
+
+bool TypeDatabase::isArgumentTypeRejected(const QString& className, const QString& typeName,
+ QString *reason) const
+{
+ return findRejection(m_rejections, TypeRejection::ArgumentType, className, typeName, reason);
+}
+
+bool TypeDatabase::isReturnTypeRejected(const QString& className, const QString& typeName,
+ QString *reason) const
+{
+ return findRejection(m_rejections, TypeRejection::ReturnType, className, typeName, reason);
+}
+
+FlagsTypeEntry* TypeDatabase::findFlagsType(const QString &name) const
+{
+ TypeEntry *fte = findType(name);
+ if (!fte) {
+ fte = m_flagsEntries.value(name);
+ if (!fte) {
+ //last hope, search for flag without scope inside of flags hash
+ for (SingleTypeEntryHash::const_iterator it = m_flagsEntries.cbegin(), end = m_flagsEntries.cend(); it != end; ++it) {
+ if (it.key().endsWith(name)) {
+ fte = it.value();
+ break;
+ }
+ }
+ }
+ }
+ return static_cast<FlagsTypeEntry *>(fte);
+}
+
+void TypeDatabase::addFlagsType(FlagsTypeEntry *fte)
+{
+ m_flagsEntries[fte->originalName()] = fte;
+}
+
+void TypeDatabase::addTemplate(TemplateEntry *t)
+{
+ m_templates[t->name()] = t;
+}
+
+void TypeDatabase::addGlobalUserFunctions(const AddedFunctionList &functions)
+{
+ m_globalUserFunctions << functions;
+}
+
+AddedFunctionList TypeDatabase::findGlobalUserFunctions(const QString& name) const
+{
+ AddedFunctionList addedFunctions;
+ for (const AddedFunction &func : m_globalUserFunctions) {
+ if (func.name() == name)
+ addedFunctions.append(func);
+ }
+ return addedFunctions;
+}
+
+void TypeDatabase::addGlobalUserFunctionModifications(const FunctionModificationList &functionModifications)
+{
+ m_functionMods << functionModifications;
+}
+
+QString TypeDatabase::globalNamespaceClassName(const TypeEntry * /*entry*/)
+{
+ return QLatin1String("Global");
+}
+
+FunctionModificationList TypeDatabase::functionModifications(const QString& signature) const
+{
+ FunctionModificationList lst;
+ for (int i = 0; i < m_functionMods.count(); ++i) {
+ const FunctionModification& mod = m_functionMods.at(i);
+ if (mod.signature == signature)
+ lst << mod;
+ }
+
+ return lst;
+}
+
+void TypeDatabase::addSuppressedWarning(const QString &s)
+{
+ m_suppressedWarnings.append(s);
+}
+
+bool TypeDatabase::isSuppressedWarning(const QString& s) const
+{
+ if (!m_suppressWarnings)
+ return false;
+
+ for (QString warning : m_suppressedWarnings) {
+ warning.replace(QLatin1String("\\*"), QLatin1String("&place_holder_for_asterisk;"));
+
+ QStringList segs = warning.split(QLatin1Char('*'), QString::SkipEmptyParts);
+ if (!segs.size())
+ continue;
+
+ int i = 0;
+ int pos = s.indexOf(QString(segs.at(i++)).replace(QLatin1String("&place_holder_for_asterisk;"), QLatin1String("*")));
+ //qDebug() << "s == " << s << ", warning == " << segs;
+ while (pos != -1) {
+ if (i == segs.size())
+ return true;
+ pos = s.indexOf(QString(segs.at(i++)).replace(QLatin1String("&place_holder_for_asterisk;"), QLatin1String("*")), pos);
+ }
+ }
+
+ return false;
+}
+
+QString TypeDatabase::modifiedTypesystemFilepath(const QString& tsFile) const
+{
+ const QFileInfo tsFi(tsFile);
+ if (tsFi.isAbsolute()) // No point in further lookups
+ return tsFi.absoluteFilePath();
+ if (tsFi.isFile()) // Make path absolute
+ return tsFi.absoluteFilePath();
+ const QString fileName = tsFi.fileName();
+ for (const QString &path : m_typesystemPaths) {
+ const QFileInfo fi(path + QLatin1Char('/') + fileName);
+ if (fi.isFile())
+ return fi.absoluteFilePath();
+ }
+ return tsFile;
+}
+
+bool TypeDatabase::parseFile(const QString &filename, bool generate)
+{
+ QString filepath = modifiedTypesystemFilepath(filename);
+ if (m_parsedTypesystemFiles.contains(filepath))
+ return m_parsedTypesystemFiles[filepath];
+
+ m_parsedTypesystemFiles[filepath] = true; // Prevent recursion when including self.
+
+ QFile file(filepath);
+ if (!file.exists()) {
+ m_parsedTypesystemFiles[filepath] = false;
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't find " << filename << ", typesystem paths: " << m_typesystemPaths.join(QLatin1String(", "));
+ return false;
+ }
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_parsedTypesystemFiles[filepath] = false;
+ qCWarning(lcShiboken).noquote().nospace()
+ << "Can't open " << QDir::toNativeSeparators(filename) << ": " << file.errorString();
+ return false;
+ }
+
+ int count = m_entries.size();
+ bool ok = parseFile(&file, generate);
+ m_parsedTypesystemFiles[filepath] = ok;
+ int newCount = m_entries.size();
+
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
+ qCDebug(lcShiboken)
+ << QStringLiteral("Parsed: '%1', %2 new entries").arg(filename).arg(newCount - count);
+ }
+ return ok;
+}
+
+bool TypeDatabase::parseFile(QIODevice* device, bool generate)
+{
+ QXmlStreamReader reader(device);
+ Handler handler(this, generate);
+ return handler.parse(reader);
+}
+
+PrimitiveTypeEntry *TypeDatabase::findPrimitiveType(const QString& name) const
+{
+ const TypeEntryList &entries = findTypes(name);
+
+ for (TypeEntry *entry : entries) {
+ if (entry && entry->isPrimitive() && static_cast<PrimitiveTypeEntry*>(entry)->preferredTargetLangType())
+ return static_cast<PrimitiveTypeEntry*>(entry);
+ }
+
+ return 0;
+}
+
+ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const
+{
+ const TypeEntryList &entries = findTypes(name);
+ for (TypeEntry *entry : entries) {
+ if (entry && entry->isComplex())
+ return static_cast<ComplexTypeEntry*>(entry);
+ }
+ return 0;
+}
+
+ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const
+{
+ const TypeEntryList &entries = findTypes(name);
+ for (TypeEntry *entry : entries) {
+ if (entry && entry->isObject())
+ return static_cast<ObjectTypeEntry*>(entry);
+ }
+ return 0;
+}
+
+NamespaceTypeEntry* TypeDatabase::findNamespaceType(const QString& name) const
+{
+ const TypeEntryList &entries = findTypes(name);
+ for (TypeEntry *entry : entries) {
+ if (entry && entry->isNamespace())
+ return static_cast<NamespaceTypeEntry*>(entry);
+ }
+ return 0;
+}
+
+bool TypeDatabase::shouldDropTypeEntry(const QString& fullTypeName) const
+{
+ return m_dropTypeEntries.contains(fullTypeName);
+}
+
+void TypeDatabase::setDropTypeEntries(QStringList dropTypeEntries)
+{
+ m_dropTypeEntries = dropTypeEntries;
+ m_dropTypeEntries.sort();
+}
+
+// Using std::pair to save some memory
+// the pair means (revision, typeIndex)
+// This global variable exists only because we can't break the ABI
+typedef QHash<const TypeEntry*, std::pair<int, int> > TypeRevisionMap;
+Q_GLOBAL_STATIC(TypeRevisionMap, typeEntryFields);
+static bool computeTypeIndexes = true;
+static int maxTypeIndex;
+
+int getTypeRevision(const TypeEntry* typeEntry)
+{
+ return typeEntryFields()->value(typeEntry).first;
+}
+
+void setTypeRevision(TypeEntry* typeEntry, int revision)
+{
+ (*typeEntryFields())[typeEntry].first = revision;
+ computeTypeIndexes = true;
+}
+
+static bool compareTypeEntriesByName(const TypeEntry* t1, const TypeEntry* t2)
+{
+ return t1->qualifiedCppName() < t2->qualifiedCppName();
+}
+
+static void _computeTypeIndexes()
+{
+ TypeDatabase* tdb = TypeDatabase::instance();
+ typedef QMap<int, TypeEntryList> GroupedTypeEntries;
+ GroupedTypeEntries groupedEntries;
+
+ // Group type entries by revision numbers
+ const TypeEntryHash &allEntries = tdb->allEntries();
+ for (TypeEntryHash::const_iterator tit = allEntries.cbegin(), end = allEntries.cend(); tit != end; ++tit) {
+ for (TypeEntry *entry : tit.value()) {
+ if (entry->isPrimitive()
+ || entry->isContainer()
+ || entry->isFunction()
+ || !entry->generateCode()
+ || entry->isEnumValue()
+ || entry->isVarargs()
+ || entry->isTypeSystem()
+ || entry->isVoid()
+ || entry->isCustom())
+ continue;
+ groupedEntries[getTypeRevision(entry)] << entry;
+ }
+ }
+
+ maxTypeIndex = 0;
+ GroupedTypeEntries::iterator it = groupedEntries.begin();
+ for (; it != groupedEntries.end(); ++it) {
+ // Remove duplicates
+ TypeEntryList::iterator newEnd = std::unique(it.value().begin(), it.value().end());
+ it.value().erase(newEnd, it.value().end());
+ // Sort the type entries by name
+ qSort(it.value().begin(), newEnd, compareTypeEntriesByName);
+
+ for (TypeEntry *entry : qAsConst(it.value())) {
+ (*typeEntryFields())[entry].second = maxTypeIndex++;
+ }
+ }
+ computeTypeIndexes = false;
+}
+
+int getTypeIndex(const TypeEntry* typeEntry)
+{
+ if (computeTypeIndexes)
+ _computeTypeIndexes();
+ return typeEntryFields()->value(typeEntry).second;
+}
+
+int getMaxTypeIndex()
+{
+ if (computeTypeIndexes)
+ _computeTypeIndexes();
+ return maxTypeIndex;
+}
+
+bool TypeDatabase::setApiVersion(const QString& packageWildcardPattern, const QString &version)
+{
+ const QString packagePattern = wildcardToRegExp(packageWildcardPattern.trimmed());
+ const QVersionNumber versionNumber = QVersionNumber::fromString(version);
+ if (versionNumber.isNull())
+ return false;
+ ApiVersions &versions = *apiVersions();
+ for (int i = 0, size = versions.size(); i < size; ++i) {
+ if (versions.at(i).first.pattern() == packagePattern) {
+ versions[i].second = versionNumber;
+ return true;
+ }
+ }
+ const QRegularExpression packageRegex(packagePattern);
+ if (!packageRegex.isValid())
+ return false;
+ versions.append(qMakePair(packageRegex, versionNumber));
+ return true;
+}
+
+bool TypeDatabase::checkApiVersion(const QString& package, const QString& version) const
+{
+ const QVersionNumber versionNumber = QVersionNumber::fromString(version);
+ if (versionNumber.isNull()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "checkApiVersion: Invalid version \"" << version << "\" specified for package "
+ << package << '.';
+ return false;
+ }
+ const ApiVersions &versions = *apiVersions();
+ for (int i = 0, size = versions.size(); i < size; ++i) {
+ if (versions.at(i).first.match(package).hasMatch())
+ return versions.at(i).second >= versionNumber;
+ }
+ return false;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeEntry *te)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "TypeEntry(";
+ if (te) {
+ d << '"' << te->qualifiedCppName() << "\", type=" << te->type();
+ if (te->include().isValid())
+ d << ", include=" << te->include();
+ const IncludeList &extraIncludes = te->extraIncludes();
+ if (const int count = extraIncludes.size()) {
+ d << ", extraIncludes[" << count << "]=";
+ for (int i = 0; i < count; ++i) {
+ if (i)
+ d << ", ";
+ d << extraIncludes.at(i);
+ }
+ }
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const TemplateEntry *te)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "TemplateEntry(";
+ if (te) {
+ d << '"' << te->name() << "\", version=" << te->version();
+ } else {
+ d << '0';
+ }
+ d << ')';
+ return d;
+}
+
+void TypeDatabase::formatDebug(QDebug &d) const
+{
+ typedef TypeEntryHash::ConstIterator Eit;
+ typedef SingleTypeEntryHash::ConstIterator Sit;
+ typedef TemplateEntryHash::ConstIterator TplIt;
+ d << "TypeDatabase("
+ << "entries[" << m_entries.size() << "]=";
+ for (Eit it = m_entries.cbegin(), end = m_entries.cend(); it != end; ++it) {
+ const int count = it.value().size();
+ d << '"' << it.key() << "\" [" << count << "]: (";
+ for (int t = 0; t < count; ++t) {
+ if (t)
+ d << ", ";
+ d << it.value().at(t);
+ }
+ d << ")\n";
+ }
+ if (!m_templates.isEmpty()) {
+ d << "templates[" << m_templates.size() << "]=(";
+ const TplIt begin = m_templates.cbegin();
+ for (TplIt it = begin, end = m_templates.cend(); it != end; ++it) {
+ if (it != begin)
+ d << ", ";
+ d << it.value();
+ }
+ d << ")\n";
+ }
+ if (!m_flagsEntries.isEmpty()) {
+ d << "flags[" << m_flagsEntries.size() << "]=(";
+ const Sit begin = m_flagsEntries.cbegin();
+ for (Sit it = begin, end = m_flagsEntries.cend(); it != end; ++it) {
+ if (it != begin)
+ d << ", ";
+ d << it.value();
+ }
+ d << ")\n";
+ }
+ d <<"\nglobalUserFunctions=" << m_globalUserFunctions << ')';
+}
+
+QDebug operator<<(QDebug d, const TypeDatabase &db)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ db.formatDebug(d);
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
diff --git a/sources/shiboken2/ApiExtractor/typedatabase.h b/sources/shiboken2/ApiExtractor/typedatabase.h
new file mode 100644
index 000000000..86f933448
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typedatabase.h
@@ -0,0 +1,186 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TYPEDATABASE_H
+#define TYPEDATABASE_H
+
+#include "apiextractormacros.h"
+#include "include.h"
+#include "typedatabase_typedefs.h"
+#include "typesystem_enums.h"
+#include "typesystem_typedefs.h"
+
+#include <QtCore/QStringList>
+
+QT_FORWARD_DECLARE_CLASS(QIODevice)
+
+class ComplexTypeEntry;
+class ContainerTypeEntry;
+class FlagsTypeEntry;
+class FunctionTypeEntry;
+class NamespaceTypeEntry;
+class ObjectTypeEntry;
+class TemplateEntry;
+class TypeEntry;
+
+struct TypeRejection;
+
+QT_FORWARD_DECLARE_CLASS(QDebug)
+
+void setTypeRevision(TypeEntry* typeEntry, int revision);
+int getTypeRevision(const TypeEntry* typeEntry);
+int getTypeIndex(const TypeEntry* typeEntry);
+int getMaxTypeIndex();
+
+class ContainerTypeEntry;
+class PrimitiveTypeEntry;
+class TypeDatabase
+{
+ TypeDatabase();
+ Q_DISABLE_COPY(TypeDatabase)
+public:
+ ~TypeDatabase();
+
+ /**
+ * Return the type system instance.
+ * \param newInstance This parameter is useful just for unit testing, because singletons causes
+ * too many side effects on unit testing.
+ */
+ static TypeDatabase* instance(bool newInstance = false);
+
+ static QString normalizedSignature(const QString &signature);
+
+ QStringList requiredTargetImports() const;
+
+ void addRequiredTargetImport(const QString& moduleName);
+
+ void addTypesystemPath(const QString& typesystem_paths);
+
+ IncludeList extraIncludes(const QString& className) const;
+
+ PrimitiveTypeEntry* findPrimitiveType(const QString& name) const;
+ ComplexTypeEntry* findComplexType(const QString& name) const;
+ ObjectTypeEntry* findObjectType(const QString& name) const;
+ NamespaceTypeEntry* findNamespaceType(const QString& name) const;
+ ContainerTypeEntry* findContainerType(const QString& name) const;
+ FunctionTypeEntry* findFunctionType(const QString& name) const;
+
+ TypeEntry* findType(const QString& name) const;
+
+ TypeEntryHash allEntries() const { return m_entries; }
+
+ SingleTypeEntryHash entries() const;
+
+ PrimitiveTypeEntryList primitiveTypes() const;
+
+ ContainerTypeEntryList containerTypes() const;
+
+ void addRejection(const TypeRejection &);
+ bool isClassRejected(const QString& className, QString *reason = nullptr) const;
+ bool isFunctionRejected(const QString& className, const QString& functionName,
+ QString *reason = nullptr) const;
+ bool isFieldRejected(const QString& className, const QString& fieldName,
+ QString *reason = nullptr) const;
+ bool isEnumRejected(const QString& className, const QString& enumName,
+ QString *reason = nullptr) const;
+ bool isArgumentTypeRejected(const QString& className, const QString& typeName,
+ QString *reason = nullptr) const;
+ bool isReturnTypeRejected(const QString& className, const QString& typeName,
+ QString *reason = nullptr) const;
+
+ void addType(TypeEntry* e);
+
+ FlagsTypeEntry* findFlagsType(const QString& name) const;
+ void addFlagsType(FlagsTypeEntry* fte);
+
+ TemplateEntry *findTemplate(const QString& name) const { return m_templates[name]; }
+
+ void addTemplate(TemplateEntry* t);
+
+ AddedFunctionList globalUserFunctions() const { return m_globalUserFunctions; }
+
+ void addGlobalUserFunctions(const AddedFunctionList &functions);
+
+ AddedFunctionList findGlobalUserFunctions(const QString& name) const;
+
+ void addGlobalUserFunctionModifications(const FunctionModificationList &functionModifications);
+
+ FunctionModificationList functionModifications(const QString& signature) const;
+
+ void setSuppressWarnings(bool on) { m_suppressWarnings = on; }
+
+ void addSuppressedWarning(const QString &s);
+
+ bool isSuppressedWarning(const QString& s) const;
+
+ static QString globalNamespaceClassName(const TypeEntry *te);
+
+ bool parseFile(const QString &filename, bool generate = true);
+ bool parseFile(QIODevice* device, bool generate = true);
+
+ bool setApiVersion(const QString& package, const QString& version);
+
+ bool checkApiVersion(const QString& package, const QString &version) const;
+
+ bool hasDroppedTypeEntries() const { return !m_dropTypeEntries.isEmpty(); }
+
+ bool shouldDropTypeEntry(const QString& fullTypeName) const;
+
+ void setDropTypeEntries(QStringList dropTypeEntries);
+
+#ifndef QT_NO_DEBUG_STREAM
+ void formatDebug(QDebug &d) const;
+#endif
+private:
+ TypeEntryList findTypes(const QString &name) const;
+ QString modifiedTypesystemFilepath(const QString &tsFile) const;
+
+ bool m_suppressWarnings;
+ TypeEntryHash m_entries;
+ SingleTypeEntryHash m_flagsEntries;
+ TemplateEntryHash m_templates;
+ QStringList m_suppressedWarnings;
+
+ AddedFunctionList m_globalUserFunctions;
+ FunctionModificationList m_functionMods;
+
+ QStringList m_requiredTargetImports;
+
+ QStringList m_typesystemPaths;
+ QHash<QString, bool> m_parsedTypesystemFiles;
+
+ QVector<TypeRejection> m_rejections;
+
+ QStringList m_dropTypeEntries;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeEntry *te);
+QDebug operator<<(QDebug d, const TypeDatabase &db);
+#endif
+#endif // TYPEDATABASE_H
diff --git a/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h b/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h
new file mode 100644
index 000000000..95859a399
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typedatabase_typedefs.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TYPEDATABASE_TYPEDEFS_H
+#define TYPEDATABASE_TYPEDEFS_H
+
+#include <QtCore/QHash>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+class ContainerTypeEntry;
+class PrimitiveTypeEntry;
+class TemplateEntry;
+class TypeEntry;
+
+typedef QVector<TypeEntry *> TypeEntryList;
+typedef QHash<QString, TypeEntryList> TypeEntryHash;
+typedef QHash<QString, TypeEntry *> SingleTypeEntryHash;
+typedef QHash<QString, TemplateEntry *> TemplateEntryHash;
+
+typedef QVector<const ContainerTypeEntry *> ContainerTypeEntryList;
+typedef QVector<const PrimitiveTypeEntry *> PrimitiveTypeEntryList;
+
+#endif // TYPEDATABASE_TYPEDEFS_H
diff --git a/sources/shiboken2/ApiExtractor/typeparser.cpp b/sources/shiboken2/ApiExtractor/typeparser.cpp
new file mode 100644
index 000000000..8165bfe44
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typeparser.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "typeparser.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QStack>
+#include <QtCore/QTextStream>
+
+class Scanner
+{
+public:
+ enum Token {
+ StarToken,
+ AmpersandToken,
+ LessThanToken,
+ ColonToken,
+ CommaToken,
+ OpenParenToken,
+ CloseParenToken,
+ SquareBegin,
+ SquareEnd,
+ GreaterThanToken,
+
+ ConstToken,
+ Identifier,
+ NoToken,
+ InvalidToken
+ };
+
+ Scanner(const QString &s)
+ : m_pos(0), m_length(s.length()), m_chars(s.constData())
+ {
+ }
+
+ Token nextToken(QString *errorMessage = Q_NULLPTR);
+ QString identifier() const;
+
+ QString msgParseError(const QString &why) const;
+
+private:
+ int m_pos;
+ int m_length;
+ int m_tokenStart;
+ const QChar *m_chars;
+};
+
+QString Scanner::identifier() const
+{
+ return QString(m_chars + m_tokenStart, m_pos - m_tokenStart);
+}
+
+Scanner::Token Scanner::nextToken(QString *errorMessage)
+{
+ Token tok = NoToken;
+
+ // remove whitespace
+ while (m_pos < m_length && m_chars[m_pos] == QLatin1Char(' '))
+ ++m_pos;
+
+ m_tokenStart = m_pos;
+
+ while (m_pos < m_length) {
+
+ const QChar &c = m_chars[m_pos];
+
+ if (tok == NoToken) {
+ switch (c.toLatin1()) {
+ case '*': tok = StarToken; break;
+ case '&': tok = AmpersandToken; break;
+ case '<': tok = LessThanToken; break;
+ case '>': tok = GreaterThanToken; break;
+ case ',': tok = CommaToken; break;
+ case '(': tok = OpenParenToken; break;
+ case ')': tok = CloseParenToken; break;
+ case '[': tok = SquareBegin; break;
+ case ']' : tok = SquareEnd; break;
+ case ':':
+ tok = ColonToken;
+ Q_ASSERT(m_pos + 1 < m_length);
+ ++m_pos;
+ break;
+ default:
+ if (c.isLetterOrNumber() || c == QLatin1Char('_')) {
+ tok = Identifier;
+ } else {
+ QString message;
+ QTextStream (&message) << ": Unrecognized character in lexer at "
+ << m_pos << " : '" << c << '\'';
+ message = msgParseError(message);
+ if (errorMessage)
+ *errorMessage = message;
+ else
+ qWarning().noquote().nospace() << message;
+ return InvalidToken;
+ }
+ break;
+ }
+ }
+
+ if (tok <= GreaterThanToken) {
+ ++m_pos;
+ break;
+ }
+
+ if (tok == Identifier) {
+ if (c.isLetterOrNumber() || c == QLatin1Char('_'))
+ ++m_pos;
+ else
+ break;
+ }
+ }
+
+ if (tok == Identifier && m_pos - m_tokenStart == 5) {
+ if (m_chars[m_tokenStart] == QLatin1Char('c')
+ && m_chars[m_tokenStart + 1] == QLatin1Char('o')
+ && m_chars[m_tokenStart + 2] == QLatin1Char('n')
+ && m_chars[m_tokenStart + 3] == QLatin1Char('s')
+ && m_chars[m_tokenStart + 4] == QLatin1Char('t'))
+ tok = ConstToken;
+ }
+
+ return tok;
+
+}
+
+QString Scanner::msgParseError(const QString &why) const
+{
+ return QStringLiteral("TypeParser: Unable to parse \"")
+ + QString(m_chars, m_length) + QStringLiteral("\": ") + why;
+}
+
+static TypeParser::Info invalidInfo()
+{
+ TypeParser::Info result;
+ result.is_busted = true;
+ return result;
+}
+
+TypeParser::Info TypeParser::parse(const QString &str, QString *errorMessage)
+{
+ Scanner scanner(str);
+
+ Info info;
+ QStack<Info *> stack;
+ stack.push(&info);
+
+ bool colon_prefix = false;
+ bool in_array = false;
+ QString array;
+
+ Scanner::Token tok = scanner.nextToken(errorMessage);
+ while (tok != Scanner::NoToken) {
+ if (tok == Scanner::InvalidToken)
+ return invalidInfo();
+
+// switch (tok) {
+// case Scanner::StarToken: printf(" - *\n"); break;
+// case Scanner::AmpersandToken: printf(" - &\n"); break;
+// case Scanner::LessThanToken: printf(" - <\n"); break;
+// case Scanner::GreaterThanToken: printf(" - >\n"); break;
+// case Scanner::ColonToken: printf(" - ::\n"); break;
+// case Scanner::CommaToken: printf(" - ,\n"); break;
+// case Scanner::ConstToken: printf(" - const\n"); break;
+// case Scanner::SquareBegin: printf(" - [\n"); break;
+// case Scanner::SquareEnd: printf(" - ]\n"); break;
+// case Scanner::Identifier: printf(" - '%s'\n", qPrintable(scanner.identifier())); break;
+// default:
+// break;
+// }
+
+ switch (tok) {
+
+ case Scanner::StarToken:
+ ++stack.top()->indirections;
+ break;
+
+ case Scanner::AmpersandToken:
+ switch (stack.top()->referenceType) {
+ case NoReference:
+ stack.top()->referenceType = LValueReference;
+ break;
+ case LValueReference:
+ stack.top()->referenceType = RValueReference;
+ break;
+ case RValueReference:
+ const QString message = scanner.msgParseError(QStringLiteral("Too many '&' qualifiers"));
+ if (errorMessage)
+ *errorMessage = message;
+ else
+ qWarning().noquote().nospace() << message;
+ return invalidInfo();
+ }
+ break;
+ case Scanner::LessThanToken:
+ stack.top()->template_instantiations << Info();
+ stack.push(&stack.top()->template_instantiations.last());
+ break;
+
+ case Scanner::CommaToken:
+ stack.pop();
+ stack.top()->template_instantiations << Info();
+ stack.push(&stack.top()->template_instantiations.last());
+ break;
+
+ case Scanner::GreaterThanToken:
+ stack.pop();
+ break;
+
+ case Scanner::ColonToken:
+ colon_prefix = true;
+ break;
+
+ case Scanner::ConstToken:
+ stack.top()->is_constant = true;
+ break;
+
+ case Scanner::OpenParenToken: // function pointers not supported
+ case Scanner::CloseParenToken: {
+ const QString message = scanner.msgParseError(QStringLiteral("Function pointers are not supported"));
+ if (errorMessage)
+ *errorMessage = message;
+ else
+ qWarning().noquote().nospace() << message;
+ return invalidInfo();
+ }
+
+ case Scanner::Identifier:
+ if (in_array) {
+ array = scanner.identifier();
+ } else if (colon_prefix || stack.top()->qualified_name.isEmpty()) {
+ stack.top()->qualified_name << scanner.identifier();
+ colon_prefix = false;
+ } else {
+ stack.top()->qualified_name.last().append(QLatin1Char(' ') + scanner.identifier());
+ }
+ break;
+
+ case Scanner::SquareBegin:
+ in_array = true;
+ break;
+
+ case Scanner::SquareEnd:
+ in_array = false;
+ stack.top()->arrays += array;
+ break;
+
+
+ default:
+ break;
+ }
+
+ tok = scanner.nextToken();
+ }
+
+ return info;
+}
+
+QString TypeParser::Info::instantiationName() const
+{
+ QString s(qualified_name.join(QLatin1String("::")));
+ if (!template_instantiations.isEmpty()) {
+ QStringList insts;
+ for (const Info &info : template_instantiations)
+ insts << info.toString();
+ s += QLatin1String("< ") + insts.join(QLatin1String(", ")) + QLatin1String(" >");
+ }
+
+ return s;
+}
+
+QString TypeParser::Info::toString() const
+{
+ QString s;
+
+ if (is_constant)
+ s += QLatin1String("const ");
+ s += instantiationName();
+ for (int i = 0; i < arrays.size(); ++i)
+ s += QLatin1Char('[') + arrays.at(i) + QLatin1Char(']');
+ s += QString(indirections, QLatin1Char('*'));
+ switch (referenceType) {
+ case NoReference:
+ break;
+ case LValueReference:
+ s += QLatin1Char('&');
+ break;
+ case RValueReference:
+ s += QLatin1String("&&");
+ break;
+ }
+ return s;
+}
diff --git a/sources/shiboken2/ApiExtractor/typeparser.h b/sources/shiboken2/ApiExtractor/typeparser.h
new file mode 100644
index 000000000..f42c42a5e
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typeparser.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TYPEPARSER_H
+#define TYPEPARSER_H
+
+#include "parser/codemodel_enums.h"
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QVector>
+
+class TypeParser
+{
+public:
+ struct Info
+ {
+ Info() : referenceType(NoReference), is_constant(false), is_busted(false), indirections(0) { }
+ QStringList qualified_name;
+ QStringList arrays;
+ QVector<Info> template_instantiations;
+ ReferenceType referenceType;
+ uint is_constant : 1;
+ uint is_busted : 1;
+ uint indirections : 6;
+
+ QString toString() const;
+ QString instantiationName() const;
+ };
+
+ static Info parse(const QString &str, QString *errorMessage = Q_NULLPTR);
+};
+
+#endif // TYPEPARSER_H
diff --git a/sources/shiboken2/ApiExtractor/typesystem.cpp b/sources/shiboken2/ApiExtractor/typesystem.cpp
new file mode 100644
index 000000000..3ec82c56d
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typesystem.cpp
@@ -0,0 +1,2737 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "typesystem.h"
+#include "typesystem_p.h"
+#include "typedatabase.h"
+#include "reporthandler.h"
+#include <QtCore/QDir>
+#include <QtCore/QFile>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QXmlStreamAttributes>
+#include <QtCore/QXmlStreamReader>
+
+static QString strings_Object = QLatin1String("Object");
+static QString strings_String = QLatin1String("String");
+static QString strings_char = QLatin1String("char");
+static QString strings_jchar = QLatin1String("jchar");
+static QString strings_jobject = QLatin1String("jobject");
+
+static inline QString colonColon() { return QStringLiteral("::"); }
+static inline QString quoteAfterLineAttribute() { return QStringLiteral("quote-after-line"); }
+static inline QString quoteBeforeLineAttribute() { return QStringLiteral("quote-before-line"); }
+static inline QString nameAttribute() { return QStringLiteral("name"); }
+static inline QString sinceAttribute() { return QStringLiteral("since"); }
+static inline QString flagsAttribute() { return QStringLiteral("flags"); }
+static inline QString classAttribute() { return QStringLiteral("class"); }
+static inline QString functionNameAttribute() { return QStringLiteral("function-name"); }
+static inline QString fieldNameAttribute() { return QStringLiteral("field-name"); }
+static inline QString enumNameAttribute() { return QStringLiteral("enum-name"); }
+static inline QString argumentTypeAttribute() { return QStringLiteral("argument-type"); }
+static inline QString returnTypeAttribute() { return QStringLiteral("return-type"); }
+
+static QVector<CustomConversion *> customConversionsForReview;
+
+// Set a regular expression for rejection from text. By legacy, those are fixed
+// strings, except for '*' meaning 'match all'. Enclosing in "^..$"
+// indicates regular expression.
+static bool setRejectionRegularExpression(const QString &patternIn,
+ QRegularExpression *re,
+ QString *errorMessage)
+{
+ QString pattern;
+ if (patternIn.startsWith(QLatin1Char('^')) && patternIn.endsWith(QLatin1Char('$')))
+ pattern = patternIn;
+ else if (patternIn == QLatin1String("*"))
+ pattern = QStringLiteral("^.*$");
+ else
+ pattern = QLatin1Char('^') + QRegularExpression::escape(patternIn) + QLatin1Char('$');
+ re->setPattern(pattern);
+ if (!re->isValid()) {
+ *errorMessage = QLatin1String("Invalid pattern \"") + patternIn
+ + QLatin1String("\": ") + re->errorString();
+ return false;
+ }
+ return true;
+}
+
+static bool addRejection(TypeDatabase *database, const QHash<QString, QString> &attributes,
+ QString *errorMessage)
+{
+ typedef QPair<QString, TypeRejection::MatchType> AttributeMatchTypePair;
+
+ TypeRejection rejection;
+
+ const QString className = attributes.value(classAttribute());
+ if (!setRejectionRegularExpression(className, &rejection.className, errorMessage))
+ return false;
+
+ static const AttributeMatchTypePair attributeMatchTypeMapping[] =
+ {{functionNameAttribute(), TypeRejection::Function},
+ {fieldNameAttribute(), TypeRejection::Field},
+ {enumNameAttribute(), TypeRejection::Enum},
+ {argumentTypeAttribute(), TypeRejection::ArgumentType},
+ {returnTypeAttribute(), TypeRejection::ReturnType}
+ };
+
+ // Search for non-empty attribute (function, field, enum)
+ const auto aend = attributes.cend();
+ for (const AttributeMatchTypePair &mapping : attributeMatchTypeMapping) {
+ const auto it = attributes.constFind(mapping.first);
+ if (it != aend && !it.value().isEmpty()) {
+ if (!setRejectionRegularExpression(it.value(), &rejection.pattern, errorMessage))
+ return false;
+ rejection.matchType = mapping.second;
+ database->addRejection(rejection);
+ return true;
+ }
+ }
+
+ // Special case: When all fields except class are empty, completely exclude class
+ if (className == QLatin1String("*")) {
+ *errorMessage = QLatin1String("bad reject entry, neither 'class', 'function-name'"
+ " nor 'field' specified");
+ return false;
+ }
+ rejection.matchType = TypeRejection::ExcludeClass;
+ database->addRejection(rejection);
+ return true;
+}
+
+
+Handler::Handler(TypeDatabase* database, bool generate)
+ : m_database(database), m_generate(generate ? TypeEntry::GenerateAll : TypeEntry::GenerateForSubclass)
+{
+ m_currentEnum = 0;
+ m_current = 0;
+ m_currentDroppedEntry = 0;
+ m_currentDroppedEntryDepth = 0;
+ m_ignoreDepth = 0;
+
+ tagNames.insert(QLatin1String("rejection"), StackElement::Rejection);
+ tagNames.insert(QLatin1String("custom-type"), StackElement::CustomTypeEntry);
+ tagNames.insert(QLatin1String("primitive-type"), StackElement::PrimitiveTypeEntry);
+ tagNames.insert(QLatin1String("container-type"), StackElement::ContainerTypeEntry);
+ tagNames.insert(QLatin1String("object-type"), StackElement::ObjectTypeEntry);
+ tagNames.insert(QLatin1String("value-type"), StackElement::ValueTypeEntry);
+ tagNames.insert(QLatin1String("interface-type"), StackElement::InterfaceTypeEntry);
+ tagNames.insert(QLatin1String("namespace-type"), StackElement::NamespaceTypeEntry);
+ tagNames.insert(QLatin1String("enum-type"), StackElement::EnumTypeEntry);
+ tagNames.insert(QLatin1String("smart-pointer-type"), StackElement::SmartPointerTypeEntry);
+ tagNames.insert(QLatin1String("function"), StackElement::FunctionTypeEntry);
+ tagNames.insert(QLatin1String("extra-includes"), StackElement::ExtraIncludes);
+ tagNames.insert(QLatin1String("include"), StackElement::Include);
+ tagNames.insert(QLatin1String("inject-code"), StackElement::InjectCode);
+ tagNames.insert(QLatin1String("modify-function"), StackElement::ModifyFunction);
+ tagNames.insert(QLatin1String("modify-field"), StackElement::ModifyField);
+ tagNames.insert(QLatin1String("access"), StackElement::Access);
+ tagNames.insert(QLatin1String("remove"), StackElement::Removal);
+ tagNames.insert(QLatin1String("rename"), StackElement::Rename);
+ tagNames.insert(QLatin1String("typesystem"), StackElement::Root);
+ tagNames.insert(QLatin1String("custom-constructor"), StackElement::CustomMetaConstructor);
+ tagNames.insert(QLatin1String("custom-destructor"), StackElement::CustomMetaDestructor);
+ tagNames.insert(QLatin1String("argument-map"), StackElement::ArgumentMap);
+ tagNames.insert(QLatin1String("suppress-warning"), StackElement::SuppressedWarning);
+ tagNames.insert(QLatin1String("load-typesystem"), StackElement::LoadTypesystem);
+ tagNames.insert(QLatin1String("define-ownership"), StackElement::DefineOwnership);
+ tagNames.insert(QLatin1String("replace-default-expression"), StackElement::ReplaceDefaultExpression);
+ tagNames.insert(QLatin1String("reject-enum-value"), StackElement::RejectEnumValue);
+ tagNames.insert(QLatin1String("replace-type"), StackElement::ReplaceType);
+ tagNames.insert(QLatin1String("conversion-rule"), StackElement::ConversionRule);
+ tagNames.insert(QLatin1String("native-to-target"), StackElement::NativeToTarget);
+ tagNames.insert(QLatin1String("target-to-native"), StackElement::TargetToNative);
+ tagNames.insert(QLatin1String("add-conversion"), StackElement::AddConversion);
+ tagNames.insert(QLatin1String("modify-argument"), StackElement::ModifyArgument);
+ tagNames.insert(QLatin1String("remove-argument"), StackElement::RemoveArgument);
+ tagNames.insert(QLatin1String("remove-default-expression"), StackElement::RemoveDefaultExpression);
+ tagNames.insert(QLatin1String("template"), StackElement::Template);
+ tagNames.insert(QLatin1String("insert-template"), StackElement::TemplateInstanceEnum);
+ tagNames.insert(QLatin1String("replace"), StackElement::Replace);
+ tagNames.insert(QLatin1String("no-null-pointer"), StackElement::NoNullPointers);
+ tagNames.insert(QLatin1String("reference-count"), StackElement::ReferenceCount);
+ tagNames.insert(QLatin1String("parent"), StackElement::ParentOwner);
+ tagNames.insert(QLatin1String("inject-documentation"), StackElement::InjectDocumentation);
+ tagNames.insert(QLatin1String("modify-documentation"), StackElement::ModifyDocumentation);
+ tagNames.insert(QLatin1String("add-function"), StackElement::AddFunction);
+}
+
+static QString msgReaderError(const QXmlStreamReader &reader, const QString &what)
+{
+ QString message;
+ QTextStream str(&message);
+ str << "Error: ";
+ if (const QFile *file = qobject_cast<const QFile *>(reader.device()))
+ str << "file=" << QDir::toNativeSeparators(file->fileName()) << ", ";
+ str << "line=" << reader.lineNumber() << ", column=" << reader.columnNumber()
+ << ", message=" << what;
+ return message;
+}
+
+static QString msgReaderError(const QXmlStreamReader &reader)
+{
+ return msgReaderError(reader, reader.errorString());
+}
+
+bool Handler::parse(QXmlStreamReader &reader)
+{
+ m_error.clear();
+ while (!reader.atEnd()) {
+ switch (reader.readNext()) {
+ case QXmlStreamReader::NoToken:
+ case QXmlStreamReader::Invalid:
+ qCWarning(lcShiboken).noquote().nospace() << msgReaderError(reader);
+ return false;
+ case QXmlStreamReader::StartElement:
+ if (!startElement(reader.name(), reader.attributes())) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+
+ break;
+ case QXmlStreamReader::EndElement:
+ if (!endElement(reader.name())) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+ break;
+ case QXmlStreamReader::Characters:
+ if (!characters(reader.text())) {
+ m_error = msgReaderError(reader, m_error);
+ return false;
+ }
+ break;
+ case QXmlStreamReader::StartDocument:
+ case QXmlStreamReader::EndDocument:
+ case QXmlStreamReader::Comment:
+ case QXmlStreamReader::DTD:
+ case QXmlStreamReader::EntityReference:
+ case QXmlStreamReader::ProcessingInstruction:
+ break;
+ }
+ }
+ return true;
+}
+
+void Handler::fetchAttributeValues(const QString &name, const QXmlStreamAttributes &atts,
+ QHash<QString, QString> *acceptedAttributes)
+{
+ Q_ASSERT(acceptedAttributes);
+
+ for (int i = 0; i < atts.length(); ++i) {
+ const QString key = atts.at(i).name().toString().toLower();
+ if (!acceptedAttributes->contains(key)) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Unknown attribute for '%1': '%2'").arg(name, key);
+ } else {
+ acceptedAttributes->insert(key, atts.at(i).value().toString());
+ }
+ }
+}
+
+bool Handler::endElement(const QStringRef &localName)
+{
+ if (m_ignoreDepth) {
+ --m_ignoreDepth;
+ return true;
+ }
+
+ if (m_currentDroppedEntry) {
+ if (m_currentDroppedEntryDepth == 1) {
+ m_current = m_currentDroppedEntry->parent;
+ delete m_currentDroppedEntry;
+ m_currentDroppedEntry = 0;
+ m_currentDroppedEntryDepth = 0;
+ } else {
+ ++m_currentDroppedEntryDepth;
+ }
+ return true;
+ }
+
+ if (!localName.compare(QLatin1String("import-file"), Qt::CaseInsensitive))
+ return true;
+
+ if (!m_current)
+ return true;
+
+ switch (m_current->type) {
+ case StackElement::Root:
+ if (m_generate == TypeEntry::GenerateAll) {
+ TypeDatabase::instance()->addGlobalUserFunctions(m_contextStack.top()->addedFunctions);
+ TypeDatabase::instance()->addGlobalUserFunctionModifications(m_contextStack.top()->functionMods);
+ for (CustomConversion *customConversion : qAsConst(customConversionsForReview)) {
+ const CustomConversion::TargetToNativeConversions &toNatives = customConversion->targetToNativeConversions();
+ for (CustomConversion::TargetToNativeConversion *toNative : toNatives)
+ toNative->setSourceType(m_database->findType(toNative->sourceTypeName()));
+ }
+ }
+ break;
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ case StackElement::NamespaceTypeEntry: {
+ ComplexTypeEntry *centry = static_cast<ComplexTypeEntry *>(m_current->entry);
+ centry->setAddedFunctions(m_contextStack.top()->addedFunctions);
+ centry->setFunctionModifications(m_contextStack.top()->functionMods);
+ centry->setFieldModifications(m_contextStack.top()->fieldMods);
+ centry->setCodeSnips(m_contextStack.top()->codeSnips);
+ centry->setDocModification(m_contextStack.top()->docModifications);
+
+ if (centry->designatedInterface()) {
+ centry->designatedInterface()->setCodeSnips(m_contextStack.top()->codeSnips);
+ centry->designatedInterface()->setFunctionModifications(m_contextStack.top()->functionMods);
+ }
+ }
+ break;
+ case StackElement::NativeToTarget:
+ case StackElement::AddConversion: {
+ CustomConversion* customConversion = static_cast<TypeEntry*>(m_current->entry)->customConversion();
+ if (!customConversion) {
+ m_error = QLatin1String("CustomConversion object is missing.");
+ return false;
+ }
+
+ QString code = m_contextStack.top()->codeSnips.takeLast().code();
+ if (m_current->type == StackElement::AddConversion) {
+ if (customConversion->targetToNativeConversions().isEmpty()) {
+ m_error = QLatin1String("CustomConversion's target to native conversions missing.");
+ return false;
+ }
+ customConversion->targetToNativeConversions().last()->setConversion(code);
+ } else {
+ customConversion->setNativeToTargetConversion(code);
+ }
+ }
+ break;
+ case StackElement::CustomMetaConstructor: {
+ m_current->entry->setCustomConstructor(*m_current->value.customFunction);
+ delete m_current->value.customFunction;
+ }
+ break;
+ case StackElement::CustomMetaDestructor: {
+ m_current->entry->setCustomDestructor(*m_current->value.customFunction);
+ delete m_current->value.customFunction;
+ }
+ break;
+ case StackElement::EnumTypeEntry:
+ m_current->entry->setDocModification(m_contextStack.top()->docModifications);
+ m_contextStack.top()->docModifications = DocModificationList();
+ m_currentEnum = 0;
+ break;
+ case StackElement::Template:
+ m_database->addTemplate(m_current->value.templateEntry);
+ break;
+ case StackElement::TemplateInstanceEnum:
+ switch (m_current->parent->type) {
+ case StackElement::InjectCode:
+ if (m_current->parent->parent->type == StackElement::Root) {
+ CodeSnipList snips = m_current->parent->entry->codeSnips();
+ CodeSnip snip = snips.takeLast();
+ snip.addTemplateInstance(m_current->value.templateInstance);
+ snips.append(snip);
+ m_current->parent->entry->setCodeSnips(snips);
+ break;
+ }
+ case StackElement::NativeToTarget:
+ case StackElement::AddConversion:
+ m_contextStack.top()->codeSnips.last().addTemplateInstance(m_current->value.templateInstance);
+ break;
+ case StackElement::Template:
+ m_current->parent->value.templateEntry->addTemplateInstance(m_current->value.templateInstance);
+ break;
+ case StackElement::CustomMetaConstructor:
+ case StackElement::CustomMetaDestructor:
+ m_current->parent->value.customFunction->addTemplateInstance(m_current->value.templateInstance);
+ break;
+ case StackElement::ConversionRule:
+ m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addTemplateInstance(m_current->value.templateInstance);
+ break;
+ case StackElement::InjectCodeInFunction:
+ m_contextStack.top()->functionMods.last().snips.last().addTemplateInstance(m_current->value.templateInstance);
+ break;
+ default:
+ break; // nada
+ };
+ break;
+ default:
+ break;
+ }
+
+ if (m_current->type == StackElement::Root
+ || m_current->type == StackElement::NamespaceTypeEntry
+ || m_current->type == StackElement::InterfaceTypeEntry
+ || m_current->type == StackElement::ObjectTypeEntry
+ || m_current->type == StackElement::ValueTypeEntry
+ || m_current->type == StackElement::PrimitiveTypeEntry) {
+ StackElementContext* context = m_contextStack.pop();
+ delete context;
+ }
+
+ StackElement *child = m_current;
+ m_current = m_current->parent;
+ delete(child);
+
+ return true;
+}
+
+template <class String> // QString/QStringRef
+bool Handler::characters(const String &ch)
+{
+ if (m_currentDroppedEntry || m_ignoreDepth)
+ return true;
+
+ if (m_current->type == StackElement::Template) {
+ m_current->value.templateEntry->addCode(ch);
+ return true;
+ }
+
+ if (m_current->type == StackElement::CustomMetaConstructor || m_current->type == StackElement::CustomMetaDestructor) {
+ m_current->value.customFunction->addCode(ch);
+ return true;
+ }
+
+ if (m_current->type == StackElement::ConversionRule
+ && m_current->parent->type == StackElement::ModifyArgument) {
+ m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.last().addCode(ch);
+ return true;
+ }
+
+ if (m_current->type == StackElement::NativeToTarget || m_current->type == StackElement::AddConversion) {
+ m_contextStack.top()->codeSnips.last().addCode(ch);
+ return true;
+ }
+
+ if (m_current->parent) {
+ if ((m_current->type & StackElement::CodeSnipMask)) {
+ CodeSnipList snips;
+ switch (m_current->parent->type) {
+ case StackElement::Root:
+ snips = m_current->parent->entry->codeSnips();
+ snips.last().addCode(ch);
+ m_current->parent->entry->setCodeSnips(snips);
+ break;
+ case StackElement::ModifyFunction:
+ case StackElement::AddFunction:
+ m_contextStack.top()->functionMods.last().snips.last().addCode(ch);
+ m_contextStack.top()->functionMods.last().modifiers |= FunctionModification::CodeInjection;
+ break;
+ case StackElement::NamespaceTypeEntry:
+ case StackElement::ObjectTypeEntry:
+ case StackElement::ValueTypeEntry:
+ case StackElement::InterfaceTypeEntry:
+ m_contextStack.top()->codeSnips.last().addCode(ch);
+ break;
+ default:
+ Q_ASSERT(false);
+ };
+ return true;
+ }
+ }
+
+ if (m_current->type & StackElement::DocumentationMask)
+ m_contextStack.top()->docModifications.last().setCode(ch);
+
+ return true;
+}
+
+bool Handler::importFileElement(const QXmlStreamAttributes &atts)
+{
+ const QString fileName = atts.value(nameAttribute()).toString();
+ if (fileName.isEmpty()) {
+ m_error = QLatin1String("Required attribute 'name' missing for include-file tag.");
+ return false;
+ }
+
+ QFile file(fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ file.setFileName(QLatin1String(":/trolltech/generator/") + fileName);
+ if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ m_error = QString::fromLatin1("Could not open file: '%1'").arg(QDir::toNativeSeparators(fileName));
+ return false;
+ }
+ }
+
+ const QStringRef quoteFrom = atts.value(quoteAfterLineAttribute());
+ bool foundFromOk = quoteFrom.isEmpty();
+ bool from = quoteFrom.isEmpty();
+
+ const QStringRef quoteTo = atts.value(quoteBeforeLineAttribute());
+ bool foundToOk = quoteTo.isEmpty();
+ bool to = true;
+
+ QTextStream in(&file);
+ while (!in.atEnd()) {
+ QString line = in.readLine();
+ if (from && to && line.contains(quoteTo)) {
+ to = false;
+ foundToOk = true;
+ break;
+ }
+ if (from && to)
+ characters(line + QLatin1Char('\n'));
+ if (!from && line.contains(quoteFrom)) {
+ from = true;
+ foundFromOk = true;
+ }
+ }
+ if (!foundFromOk || !foundToOk) {
+ QString fromError = QStringLiteral("Could not find quote-after-line='%1' in file '%2'.")
+ .arg(quoteFrom.toString(), fileName);
+ QString toError = QStringLiteral("Could not find quote-before-line='%1' in file '%2'.")
+ .arg(quoteTo.toString(), fileName);
+
+ if (!foundToOk)
+ m_error = toError;
+ if (!foundFromOk)
+ m_error = fromError;
+ if (!foundFromOk && !foundToOk)
+ m_error = fromError + QLatin1Char(' ') + toError;
+ return false;
+ }
+
+ return true;
+}
+
+bool Handler::convertBoolean(const QString &_value, const QString &attributeName, bool defaultValue)
+{
+ QString value = _value.toLower();
+ if (value == QLatin1String("true") || value == QLatin1String("yes"))
+ return true;
+ else if (value == QLatin1String("false") || value == QLatin1String("no"))
+ return false;
+ else {
+ QString warn = QStringLiteral("Boolean value '%1' not supported in attribute '%2'. Use 'yes' or 'no'. Defaulting to '%3'.")
+ .arg(value, attributeName,
+ defaultValue ? QLatin1String("yes") : QLatin1String("no"));
+
+ qCWarning(lcShiboken).noquote().nospace() << warn;
+ return defaultValue;
+ }
+}
+
+static bool convertRemovalAttribute(const QString& removalAttribute, Modification& mod, QString& errorMsg)
+{
+ QString remove = removalAttribute.toLower();
+ if (!remove.isEmpty()) {
+ if (remove == QLatin1String("all")) {
+ mod.removal = TypeSystem::All;
+ } else if (remove == QLatin1String("target")) {
+ mod.removal = TypeSystem::TargetLangAndNativeCode;
+ } else {
+ errorMsg = QString::fromLatin1("Bad removal type '%1'").arg(remove);
+ return false;
+ }
+ }
+ return true;
+}
+
+static void getNamePrefixRecursive(StackElement* element, QStringList& names)
+{
+ if (!element->parent || !element->parent->entry)
+ return;
+ getNamePrefixRecursive(element->parent, names);
+ names << element->parent->entry->name();
+}
+
+static QString getNamePrefix(StackElement* element)
+{
+ QStringList names;
+ getNamePrefixRecursive(element, names);
+ return names.join(QLatin1Char('.'));
+}
+
+// Returns empty string if there's no error.
+static QString checkSignatureError(const QString& signature, const QString& tag)
+{
+ QString funcName = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
+ static const QRegularExpression whiteSpace(QStringLiteral("\\s"));
+ Q_ASSERT(whiteSpace.isValid());
+ if (!funcName.startsWith(QLatin1String("operator ")) && funcName.contains(whiteSpace)) {
+ return QString::fromLatin1("Error in <%1> tag signature attribute '%2'.\n"
+ "White spaces aren't allowed in function names, "
+ "and return types should not be part of the signature.")
+ .arg(tag, signature);
+ }
+ return QString();
+}
+
+void Handler::addFlags(const QString &name, QString flagName,
+ const QHash<QString, QString> &attributes, double since)
+{
+ FlagsTypeEntry *ftype = new FlagsTypeEntry(QLatin1String("QFlags<") + name + QLatin1Char('>'), since);
+ ftype->setOriginator(m_currentEnum);
+ // Try to get the guess the qualified flag name
+ const int lastSepPos = name.lastIndexOf(colonColon());
+ if (lastSepPos >= 0 && !flagName.contains(colonColon()))
+ flagName.prepend(name.left(lastSepPos + 2));
+
+ ftype->setOriginalName(flagName);
+ ftype->setCodeGeneration(m_generate);
+ QString n = ftype->originalName();
+
+ QStringList lst = n.split(colonColon());
+ if (QStringList(lst.mid(0, lst.size() - 1)).join(colonColon()) != m_currentEnum->targetLangQualifier()) {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("enum %1 and flags %2 differ in qualifiers")
+ // avoid constFirst to stay Qt 5.5 compatible
+ .arg(m_currentEnum->targetLangQualifier(), lst.first());
+ }
+
+ ftype->setFlagsName(lst.last());
+ m_currentEnum->setFlags(ftype);
+
+ m_database->addFlagsType(ftype);
+ m_database->addType(ftype);
+
+ QString revision = attributes.value(QLatin1String("flags-revision"));
+ if (revision.isEmpty())
+ revision = attributes.value(QLatin1String("revision"));
+ setTypeRevision(ftype, revision.toInt());
+}
+
+bool Handler::handleSmartPointerEntry(StackElement *element,
+ QHash<QString, QString> &attributes,
+ const QString &name,
+ double since)
+{
+ QString smartPointerType = attributes[QLatin1String("type")];
+ if (smartPointerType.isEmpty()) {
+ m_error = QLatin1String("No type specified for the smart pointer. Currently supported types: 'shared',");
+ return false;
+ }
+ if (smartPointerType != QLatin1String("shared")) {
+ m_error = QLatin1String("Currently only the 'shared' type is supported.");
+ return false;
+ }
+
+ QString getter = attributes[QLatin1String("getter")];
+ if (getter.isEmpty()) {
+ m_error = QLatin1String("No function getter name specified for getting the raw pointer held by the smart pointer.");
+ return false;
+ }
+
+ QString refCountMethodName = attributes[QLatin1String("ref-count-method")];
+ QString signature = getter + QLatin1String("()");
+
+ signature = TypeDatabase::normalizedSignature(signature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for the smart pointer getter found.");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature,
+ QLatin1String("smart-pointer-type"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ SmartPointerTypeEntry *type = new SmartPointerTypeEntry(name,
+ getter,
+ smartPointerType,
+ refCountMethodName,
+ since);
+ type->setTargetLangPackage(m_defaultPackage);
+ type->setCodeGeneration(m_generate);
+ element->entry = type;
+ return true;
+}
+
+bool Handler::startElement(const QStringRef &n, const QXmlStreamAttributes &atts)
+{
+ if (m_ignoreDepth) {
+ ++m_ignoreDepth;
+ return true;
+ }
+
+ if (!m_defaultPackage.isEmpty() && atts.hasAttribute(sinceAttribute())) {
+ TypeDatabase* td = TypeDatabase::instance();
+ if (!td->checkApiVersion(m_defaultPackage, atts.value(sinceAttribute()).toString())) {
+ ++m_ignoreDepth;
+ return true;
+ }
+ }
+
+ const QString tagName = n.toString().toLower();
+ if (tagName == QLatin1String("import-file"))
+ return importFileElement(atts);
+
+ const QHash<QString, StackElement::ElementType>::const_iterator tit = tagNames.constFind(tagName);
+ if (tit == tagNames.constEnd()) {
+ m_error = QStringLiteral("Unknown tag name: '%1'").arg(tagName);
+ return false;
+ }
+
+ if (m_currentDroppedEntry) {
+ ++m_currentDroppedEntryDepth;
+ return true;
+ }
+
+ StackElement* element = new StackElement(m_current);
+ element->type = tit.value();
+
+ if (element->type == StackElement::Root && m_generate == TypeEntry::GenerateAll)
+ customConversionsForReview.clear();
+
+ if (element->type == StackElement::Root
+ || element->type == StackElement::NamespaceTypeEntry
+ || element->type == StackElement::InterfaceTypeEntry
+ || element->type == StackElement::ObjectTypeEntry
+ || element->type == StackElement::ValueTypeEntry
+ || element->type == StackElement::PrimitiveTypeEntry) {
+ m_contextStack.push(new StackElementContext());
+ }
+
+ if (element->type & StackElement::TypeEntryMask) {
+ QHash<QString, QString> attributes;
+ attributes.insert(nameAttribute(), QString());
+ attributes.insert(QLatin1String("revision"), QLatin1String("0"));
+ attributes.insert(sinceAttribute(), QLatin1String("0"));
+
+ switch (element->type) {
+ case StackElement::PrimitiveTypeEntry:
+ attributes.insert(QLatin1String("target-lang-name"), QString());
+ attributes.insert(QLatin1String("target-lang-api-name"), QString());
+ attributes.insert(QLatin1String("preferred-conversion"), QLatin1String("yes"));
+ attributes.insert(QLatin1String("preferred-target-lang-type"), QLatin1String("yes"));
+ attributes.insert(QLatin1String("default-constructor"), QString());
+ break;
+ case StackElement::ContainerTypeEntry:
+ attributes.insert(QLatin1String("type"), QString());
+ break;
+ case StackElement::SmartPointerTypeEntry:
+ attributes.insert(QLatin1String("type"), QString());
+ attributes.insert(QLatin1String("getter"), QString());
+ attributes.insert(QLatin1String("ref-count-method"), QString());
+ break;
+ case StackElement::EnumTypeEntry:
+ attributes.insert(flagsAttribute(), QString());
+ attributes.insert(QLatin1String("flags-revision"), QString());
+ attributes.insert(QLatin1String("upper-bound"), QString());
+ attributes.insert(QLatin1String("lower-bound"), QString());
+ attributes.insert(QLatin1String("force-integer"), QLatin1String("no"));
+ attributes.insert(QLatin1String("extensible"), QLatin1String("no"));
+ attributes.insert(QLatin1String("identified-by-value"), QString());
+ break;
+ case StackElement::ValueTypeEntry:
+ attributes.insert(QLatin1String("default-constructor"), QString());
+ // fall throooough
+ case StackElement::ObjectTypeEntry:
+ attributes.insert(QLatin1String("force-abstract"), QLatin1String("no"));
+ attributes.insert(QLatin1String("deprecated"), QLatin1String("no"));
+ attributes.insert(QLatin1String("hash-function"), QString());
+ attributes.insert(QLatin1String("stream"), QLatin1String("no"));
+ // fall throooough
+ case StackElement::InterfaceTypeEntry:
+ attributes[QLatin1String("default-superclass")] = m_defaultSuperclass;
+ attributes.insert(QLatin1String("polymorphic-id-expression"), QString());
+ attributes.insert(QLatin1String("delete-in-main-thread"), QLatin1String("no"));
+ attributes.insert(QLatin1String("held-type"), QString());
+ attributes.insert(QLatin1String("copyable"), QString());
+ // fall through
+ case StackElement::NamespaceTypeEntry:
+ attributes.insert(QLatin1String("target-lang-name"), QString());
+ attributes[QLatin1String("package")] = m_defaultPackage;
+ attributes.insert(QLatin1String("expense-cost"), QLatin1String("1"));
+ attributes.insert(QLatin1String("expense-limit"), QLatin1String("none"));
+ attributes.insert(QLatin1String("polymorphic-base"), QLatin1String("no"));
+ attributes.insert(QLatin1String("generate"), QLatin1String("yes"));
+ attributes.insert(QLatin1String("target-type"), QString());
+ attributes.insert(QLatin1String("generic-class"), QLatin1String("no"));
+ break;
+ case StackElement::FunctionTypeEntry:
+ attributes.insert(QLatin1String("signature"), QString());
+ attributes.insert(QLatin1String("rename"), QString());
+ break;
+ default:
+ { } // nada
+ };
+
+ fetchAttributeValues(tagName, atts, &attributes);
+ QString name = attributes[nameAttribute()];
+ double since = attributes[sinceAttribute()].toDouble();
+
+ if (m_database->hasDroppedTypeEntries()) {
+ QString identifier = getNamePrefix(element) + QLatin1Char('.');
+ identifier += (element->type == StackElement::FunctionTypeEntry ? attributes[QLatin1String("signature")] : name);
+ if (m_database->shouldDropTypeEntry(identifier)) {
+ m_currentDroppedEntry = element;
+ m_currentDroppedEntryDepth = 1;
+ if (ReportHandler::isDebug(ReportHandler::SparseDebug)) {
+ qCDebug(lcShiboken)
+ << QStringLiteral("Type system entry '%1' was intentionally dropped from generation.").arg(identifier);
+ }
+ return true;
+ }
+ }
+
+ // The top level tag 'function' has only the 'signature' tag
+ // and we should extract the 'name' value from it.
+ if (element->type == StackElement::FunctionTypeEntry) {
+ QString signature = attributes[QLatin1String("signature")];
+ name = signature.left(signature.indexOf(QLatin1Char('('))).trimmed();
+ QString errorString = checkSignatureError(signature, QLatin1String("function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+ QString rename = attributes[QLatin1String("rename")];
+ if (!rename.isEmpty()) {
+ static const QRegularExpression functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$"));
+ Q_ASSERT(functionNameRegExp.isValid());
+ if (!functionNameRegExp.match(rename).hasMatch()) {
+ m_error = QLatin1String("can not rename '") + signature + QLatin1String("', '")
+ + rename + QLatin1String("' is not a valid function name");
+ return false;
+ }
+ FunctionModification mod(since);
+ mod.signature = signature;
+ mod.renamedToName = attributes[QLatin1String("rename")];
+ mod.modifiers |= Modification::Rename;
+ m_contextStack.top()->functionMods << mod;
+ }
+ }
+
+ // We need to be able to have duplicate primitive type entries,
+ // or it's not possible to cover all primitive target language
+ // types (which we need to do in order to support fake meta objects)
+ if (element->type != StackElement::PrimitiveTypeEntry
+ && element->type != StackElement::FunctionTypeEntry) {
+ TypeEntry *tmp = m_database->findType(name);
+ if (tmp)
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Duplicate type entry: '%1'").arg(name);
+ }
+
+ if (element->type == StackElement::EnumTypeEntry) {
+ if (name.isEmpty()) {
+ name = attributes[QLatin1String("identified-by-value")];
+ } else if (!attributes[QLatin1String("identified-by-value")].isEmpty()) {
+ m_error = QLatin1String("can't specify both 'name' and 'identified-by-value' attributes");
+ return false;
+ }
+ }
+
+ // Fix type entry name using nesting information.
+ if (element->type & StackElement::TypeEntryMask
+ && element->parent && element->parent->type != StackElement::Root) {
+ name = element->parent->entry->name() + colonColon() + name;
+ }
+
+
+ if (name.isEmpty()) {
+ m_error = QLatin1String("no 'name' attribute specified");
+ return false;
+ }
+
+ switch (element->type) {
+ case StackElement::CustomTypeEntry:
+ element->entry = new TypeEntry(name, TypeEntry::CustomType, since);
+ break;
+ case StackElement::PrimitiveTypeEntry: {
+ QString targetLangName = attributes[QLatin1String("target-lang-name")];
+ QString targetLangApiName = attributes[QLatin1String("target-lang-api-name")];
+ QString preferredConversion = attributes[QLatin1String("preferred-conversion")].toLower();
+ QString preferredTargetLangType = attributes[QLatin1String("preferred-target-lang-type")].toLower();
+ QString defaultConstructor = attributes[QLatin1String("default-constructor")];
+
+ if (targetLangName.isEmpty())
+ targetLangName = name;
+ if (targetLangApiName.isEmpty())
+ targetLangApiName = name;
+
+ PrimitiveTypeEntry *type = new PrimitiveTypeEntry(name, since);
+ type->setCodeGeneration(m_generate);
+ type->setTargetLangName(targetLangName);
+ type->setTargetLangApiName(targetLangApiName);
+ type->setTargetLangPackage(m_defaultPackage);
+ type->setDefaultConstructor(defaultConstructor);
+
+ bool preferred;
+ preferred = convertBoolean(preferredConversion, QLatin1String("preferred-conversion"), true);
+ type->setPreferredConversion(preferred);
+ preferred = convertBoolean(preferredTargetLangType,
+ QLatin1String("preferred-target-lang-type"), true);
+ type->setPreferredTargetLangType(preferred);
+
+ element->entry = type;
+ }
+ break;
+
+ case StackElement::ContainerTypeEntry: {
+ QString typeName = attributes[QLatin1String("type")];
+ ContainerTypeEntry::Type containerType =
+ ContainerTypeEntry::containerTypeFromString(typeName);
+ if (typeName.isEmpty()) {
+ m_error = QLatin1String("no 'type' attribute specified");
+ return false;
+ } else if (containerType == ContainerTypeEntry::NoContainer) {
+ m_error = QLatin1String("there is no container of type ") + typeName;
+ return false;
+ }
+
+ ContainerTypeEntry *type = new ContainerTypeEntry(name, containerType, since);
+ type->setCodeGeneration(m_generate);
+ element->entry = type;
+ }
+ break;
+
+ case StackElement::SmartPointerTypeEntry: {
+ bool result = handleSmartPointerEntry(element, attributes, name, since);
+ if (!result)
+ return result;
+ }
+ break;
+
+ case StackElement::EnumTypeEntry: {
+ QStringList names = name.split(colonColon());
+ if (names.size() == 1)
+ m_currentEnum = new EnumTypeEntry(QString(), name, since);
+ else
+ m_currentEnum =
+ new EnumTypeEntry(QStringList(names.mid(0, names.size() - 1)).join(colonColon()),
+ names.last(), since);
+ m_currentEnum->setAnonymous(!attributes[QLatin1String("identified-by-value")].isEmpty());
+ element->entry = m_currentEnum;
+ m_currentEnum->setCodeGeneration(m_generate);
+ m_currentEnum->setTargetLangPackage(m_defaultPackage);
+ m_currentEnum->setUpperBound(attributes[QLatin1String("upper-bound")]);
+ m_currentEnum->setLowerBound(attributes[QLatin1String("lower-bound")]);
+ m_currentEnum->setForceInteger(convertBoolean(attributes[QLatin1String("force-integer")], QLatin1String("force-integer"), false));
+ m_currentEnum->setExtensible(convertBoolean(attributes[QLatin1String("extensible")], QLatin1String("extensible"), false));
+
+ // put in the flags parallel...
+ const QString flagNames = attributes.value(flagsAttribute());
+ if (!flagNames.isEmpty()) {
+ const QStringList &flagNameList = flagNames.split(QLatin1Char(','));
+ for (const QString &flagName : flagNameList)
+ addFlags(name, flagName.trimmed(), attributes, since);
+ }
+ }
+ break;
+
+ case StackElement::InterfaceTypeEntry: {
+ ObjectTypeEntry *otype = new ObjectTypeEntry(name, since);
+ QString targetLangName = attributes[QLatin1String("target-lang-name")];
+ if (targetLangName.isEmpty())
+ targetLangName = name;
+ InterfaceTypeEntry *itype =
+ new InterfaceTypeEntry(InterfaceTypeEntry::interfaceName(targetLangName), since);
+
+ if (!convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true))
+ itype->setCodeGeneration(TypeEntry::GenerateForSubclass);
+ else
+ itype->setCodeGeneration(m_generate);
+ otype->setDesignatedInterface(itype);
+ itype->setOrigin(otype);
+ element->entry = otype;
+ }
+ // fall through
+ case StackElement::ValueTypeEntry: {
+ if (!element->entry) {
+ ValueTypeEntry* typeEntry = new ValueTypeEntry(name, since);
+ QString defaultConstructor = attributes[QLatin1String("default-constructor")];
+ if (!defaultConstructor.isEmpty())
+ typeEntry->setDefaultConstructor(defaultConstructor);
+ element->entry = typeEntry;
+ }
+
+ // fall through
+ case StackElement::NamespaceTypeEntry:
+ if (!element->entry)
+ element->entry = new NamespaceTypeEntry(name, since);
+
+ // fall through
+ case StackElement::ObjectTypeEntry:
+ if (!element->entry)
+ element->entry = new ObjectTypeEntry(name, since);
+
+ element->entry->setStream(attributes[QLatin1String("stream")] == QLatin1String("yes"));
+
+ ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
+ ctype->setTargetLangPackage(attributes[QLatin1String("package")]);
+ ctype->setDefaultSuperclass(attributes[QLatin1String("default-superclass")]);
+ ctype->setGenericClass(convertBoolean(attributes[QLatin1String("generic-class")], QLatin1String("generic-class"), false));
+
+ if (!convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true))
+ element->entry->setCodeGeneration(TypeEntry::GenerateForSubclass);
+ else
+ element->entry->setCodeGeneration(m_generate);
+
+ QString targetLangName = attributes[QLatin1String("target-lang-name")];
+ if (!targetLangName.isEmpty())
+ ctype->setTargetLangName(targetLangName);
+
+ // The expense policy
+ QString limit = attributes[QLatin1String("expense-limit")];
+ if (!limit.isEmpty() && limit != QLatin1String("none")) {
+ ExpensePolicy ep;
+ ep.limit = limit.toInt();
+ ep.cost = attributes[QLatin1String("expense-cost")];
+ ctype->setExpensePolicy(ep);
+ }
+
+
+ ctype->setIsPolymorphicBase(convertBoolean(attributes[QLatin1String("polymorphic-base")], QLatin1String("polymorphic-base"), false));
+ ctype->setPolymorphicIdValue(attributes[QLatin1String("polymorphic-id-expression")]);
+ //Copyable
+ if (attributes[QLatin1String("copyable")].isEmpty())
+ ctype->setCopyable(ComplexTypeEntry::Unknown);
+ else {
+ if (convertBoolean(attributes[QLatin1String("copyable")], QLatin1String("copyable"), false))
+ ctype->setCopyable(ComplexTypeEntry::CopyableSet);
+ else
+ ctype->setCopyable(ComplexTypeEntry::NonCopyableSet);
+
+ }
+
+ if (element->type == StackElement::ObjectTypeEntry || element->type == StackElement::ValueTypeEntry)
+ ctype->setHashFunction(attributes[QLatin1String("hash-function")]);
+
+
+ ctype->setHeldType(attributes[QLatin1String("held-type")]);
+
+ if (element->type == StackElement::ObjectTypeEntry
+ || element->type == StackElement::ValueTypeEntry) {
+ if (convertBoolean(attributes[QLatin1String("force-abstract")], QLatin1String("force-abstract"), false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::ForceAbstract);
+ if (convertBoolean(attributes[QLatin1String("deprecated")], QLatin1String("deprecated"), false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::Deprecated);
+ }
+
+ if (element->type == StackElement::InterfaceTypeEntry
+ || element->type == StackElement::ValueTypeEntry
+ || element->type == StackElement::ObjectTypeEntry) {
+ if (convertBoolean(attributes[QLatin1String("delete-in-main-thread")], QLatin1String("delete-in-main-thread"), false))
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DeleteInMainThread);
+ }
+
+ QString targetType = attributes[QLatin1String("target-type")];
+ if (!targetType.isEmpty() && element->entry->isComplex())
+ static_cast<ComplexTypeEntry *>(element->entry)->setTargetType(targetType);
+
+ // ctype->setInclude(Include(Include::IncludePath, ctype->name()));
+ ctype = ctype->designatedInterface();
+ if (ctype)
+ ctype->setTargetLangPackage(attributes[QLatin1String("package")]);
+
+ }
+ break;
+ case StackElement::FunctionTypeEntry: {
+ QString signature = attributes[QLatin1String("signature")];
+ signature = TypeDatabase::normalizedSignature(signature);
+ element->entry = m_database->findType(name);
+ if (element->entry) {
+ if (element->entry->type() == TypeEntry::FunctionType) {
+ reinterpret_cast<FunctionTypeEntry*>(element->entry)->addSignature(signature);
+ } else {
+ m_error = QStringLiteral("%1 expected to be a function, but isn't! Maybe it was already declared as a class or something else.")
+ .arg(name);
+ return false;
+ }
+ } else {
+ element->entry = new FunctionTypeEntry(name, signature, since);
+ element->entry->setCodeGeneration(m_generate);
+ }
+ }
+ break;
+ default:
+ Q_ASSERT(false);
+ };
+
+ if (element->entry) {
+ m_database->addType(element->entry);
+ setTypeRevision(element->entry, attributes[QLatin1String("revision")].toInt());
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << QStringLiteral("Type: %1 was rejected by typesystem").arg(name);
+ }
+
+ } else if (element->type == StackElement::InjectDocumentation) {
+ // check the XML tag attributes
+ QHash<QString, QString> attributes;
+ attributes.insert(QLatin1String("mode"), QLatin1String("replace"));
+ attributes.insert(QLatin1String("format"), QLatin1String("native"));
+ attributes.insert(sinceAttribute(), QLatin1String("0"));
+
+ fetchAttributeValues(tagName, atts, &attributes);
+ double since = attributes[sinceAttribute()].toDouble();
+
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (m_current->parent && m_current->parent->type & validParent) {
+ QString modeName = attributes[QLatin1String("mode")];
+ TypeSystem::DocModificationMode mode;
+ if (modeName == QLatin1String("append")) {
+ mode = TypeSystem::DocModificationAppend;
+ } else if (modeName == QLatin1String("prepend")) {
+ mode = TypeSystem::DocModificationPrepend;
+ } else if (modeName == QLatin1String("replace")) {
+ mode = TypeSystem::DocModificationReplace;
+ } else {
+ m_error = QLatin1String("Unknow documentation injection mode: ") + modeName;
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
+ languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
+ }
+
+ QString format = attributes[QLatin1String("format")].toLower();
+ TypeSystem::Language lang = languageNames.value(format, TypeSystem::NoLanguage);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(format);
+ return false;
+ }
+
+ QString signature = m_current->type & StackElement::TypeEntryMask ? QString() : m_currentSignature;
+ DocModification mod(mode, signature, since);
+ mod.format = lang;
+ m_contextStack.top()->docModifications << mod;
+ } else {
+ m_error = QLatin1String("inject-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type");
+ return false;
+ }
+ } else if (element->type == StackElement::ModifyDocumentation) {
+ // check the XML tag attributes
+ QHash<QString, QString> attributes;
+ attributes.insert(QLatin1String("xpath"), QString());
+ attributes.insert(sinceAttribute(), QLatin1String("0"));
+ fetchAttributeValues(tagName, atts, &attributes);
+ double since = attributes[sinceAttribute()].toDouble();
+
+ const int validParent = StackElement::TypeEntryMask
+ | StackElement::ModifyFunction
+ | StackElement::ModifyField;
+ if (m_current->parent && m_current->parent->type & validParent) {
+ QString signature = (m_current->type & StackElement::TypeEntryMask) ? QString() : m_currentSignature;
+ m_contextStack.top()->docModifications << DocModification(attributes[QLatin1String("xpath")], signature, since);
+ } else {
+ m_error = QLatin1String("modify-documentation must be inside modify-function, "
+ "modify-field or other tags that creates a type");
+ return false;
+ }
+ } else if (element->type != StackElement::None) {
+ bool topLevel = element->type == StackElement::Root
+ || element->type == StackElement::SuppressedWarning
+ || element->type == StackElement::Rejection
+ || element->type == StackElement::LoadTypesystem
+ || element->type == StackElement::InjectCode
+ || element->type == StackElement::ExtraIncludes
+ || element->type == StackElement::ConversionRule
+ || element->type == StackElement::AddFunction
+ || element->type == StackElement::Template;
+
+ if (!topLevel && m_current->type == StackElement::Root) {
+ m_error = QStringLiteral("Tag requires parent: '%1'").arg(tagName);
+ return false;
+ }
+
+ StackElement topElement = !m_current ? StackElement(0) : *m_current;
+ element->entry = topElement.entry;
+
+ QHash<QString, QString> attributes;
+ attributes.insert(sinceAttribute(), QLatin1String("0"));
+ switch (element->type) {
+ case StackElement::Root:
+ attributes.insert(QLatin1String("package"), QString());
+ attributes.insert(QLatin1String("default-superclass"), QString());
+ break;
+ case StackElement::LoadTypesystem:
+ attributes.insert(nameAttribute(), QString());
+ attributes.insert(QLatin1String("generate"), QLatin1String("yes"));
+ break;
+ case StackElement::NoNullPointers:
+ attributes.insert(QLatin1String("default-value"), QString());
+ break;
+ case StackElement::SuppressedWarning:
+ attributes.insert(QLatin1String("text"), QString());
+ break;
+ case StackElement::ReplaceDefaultExpression:
+ attributes.insert(QLatin1String("with"), QString());
+ break;
+ case StackElement::DefineOwnership:
+ attributes.insert(QLatin1String("class"), QLatin1String("target"));
+ attributes.insert(QLatin1String("owner"), QString());
+ break;
+ case StackElement::AddFunction:
+ attributes.insert(QLatin1String("signature"), QString());
+ attributes.insert(QLatin1String("return-type"), QLatin1String("void"));
+ attributes.insert(QLatin1String("access"), QLatin1String("public"));
+ attributes.insert(QLatin1String("static"), QLatin1String("no"));
+ break;
+ case StackElement::ModifyFunction:
+ attributes.insert(QLatin1String("signature"), QString());
+ attributes.insert(QLatin1String("access"), QString());
+ attributes.insert(QLatin1String("remove"), QString());
+ attributes.insert(QLatin1String("rename"), QString());
+ attributes.insert(QLatin1String("deprecated"), QLatin1String("no"));
+ attributes.insert(QLatin1String("associated-to"), QString());
+ attributes.insert(QLatin1String("virtual-slot"), QLatin1String("no"));
+ attributes.insert(QLatin1String("thread"), QLatin1String("no"));
+ attributes.insert(QLatin1String("allow-thread"), QLatin1String("no"));
+ break;
+ case StackElement::ModifyArgument:
+ attributes.insert(QLatin1String("index"), QString());
+ attributes.insert(QLatin1String("replace-value"), QString());
+ attributes.insert(QLatin1String("invalidate-after-use"), QLatin1String("no"));
+ break;
+ case StackElement::ModifyField:
+ attributes.insert(nameAttribute(), QString());
+ attributes.insert(QLatin1String("write"), QLatin1String("true"));
+ attributes.insert(QLatin1String("read"), QLatin1String("true"));
+ attributes.insert(QLatin1String("remove"), QString());
+ break;
+ case StackElement::Access:
+ attributes.insert(QLatin1String("modifier"), QString());
+ break;
+ case StackElement::Include:
+ attributes.insert(QLatin1String("file-name"), QString());
+ attributes.insert(QLatin1String("location"), QString());
+ break;
+ case StackElement::CustomMetaConstructor:
+ attributes[nameAttribute()] = topElement.entry->name().toLower() + QLatin1String("_create");
+ attributes.insert(QLatin1String("param-name"), QLatin1String("copy"));
+ break;
+ case StackElement::CustomMetaDestructor:
+ attributes[nameAttribute()] = topElement.entry->name().toLower() + QLatin1String("_delete");
+ attributes.insert(QLatin1String("param-name"), QLatin1String("copy"));
+ break;
+ case StackElement::ReplaceType:
+ attributes.insert(QLatin1String("modified-type"), QString());
+ break;
+ case StackElement::InjectCode:
+ attributes.insert(QLatin1String("class"), QLatin1String("target"));
+ attributes.insert(QLatin1String("position"), QLatin1String("beginning"));
+ attributes.insert(QLatin1String("file"), QString());
+ break;
+ case StackElement::ConversionRule:
+ attributes.insert(QLatin1String("class"), QString());
+ attributes.insert(QLatin1String("file"), QString());
+ break;
+ case StackElement::TargetToNative:
+ attributes.insert(QLatin1String("replace"), QLatin1String("yes"));
+ break;
+ case StackElement::AddConversion:
+ attributes.insert(QLatin1String("type"), QString());
+ attributes.insert(QLatin1String("check"), QString());
+ break;
+ case StackElement::RejectEnumValue:
+ attributes.insert(nameAttribute(), QString());
+ break;
+ case StackElement::ArgumentMap:
+ attributes.insert(QLatin1String("index"), QLatin1String("1"));
+ attributes.insert(QLatin1String("meta-name"), QString());
+ break;
+ case StackElement::Rename:
+ attributes.insert(QLatin1String("to"), QString());
+ break;
+ case StackElement::Rejection:
+ attributes.insert(classAttribute(), QString());
+ attributes.insert(functionNameAttribute(), QString());
+ attributes.insert(fieldNameAttribute(), QString());
+ attributes.insert(enumNameAttribute(), QString());
+ attributes.insert(argumentTypeAttribute(), QString());
+ attributes.insert(returnTypeAttribute(), QString());
+ break;
+ case StackElement::Removal:
+ attributes.insert(QLatin1String("class"), QLatin1String("all"));
+ break;
+ case StackElement::Template:
+ attributes.insert(nameAttribute(), QString());
+ break;
+ case StackElement::TemplateInstanceEnum:
+ attributes.insert(nameAttribute(), QString());
+ break;
+ case StackElement::Replace:
+ attributes.insert(QLatin1String("from"), QString());
+ attributes.insert(QLatin1String("to"), QString());
+ break;
+ case StackElement::ReferenceCount:
+ attributes.insert(QLatin1String("action"), QString());
+ attributes.insert(QLatin1String("variable-name"), QString());
+ break;
+ case StackElement::ParentOwner:
+ attributes.insert(QLatin1String("index"), QString());
+ attributes.insert(QLatin1String("action"), QString());
+ default:
+ { };
+ };
+
+ double since = 0;
+ if (attributes.count() > 0) {
+ fetchAttributeValues(tagName, atts, &attributes);
+ since = attributes[sinceAttribute()].toDouble();
+ }
+
+ switch (element->type) {
+ case StackElement::Root:
+ m_defaultPackage = attributes[QLatin1String("package")];
+ m_defaultSuperclass = attributes[QLatin1String("default-superclass")];
+ element->type = StackElement::Root;
+ {
+ TypeSystemTypeEntry* moduleEntry = reinterpret_cast<TypeSystemTypeEntry*>(
+ m_database->findType(m_defaultPackage));
+ element->entry = moduleEntry ? moduleEntry : new TypeSystemTypeEntry(m_defaultPackage, since);
+ element->entry->setCodeGeneration(m_generate);
+ }
+
+ if ((m_generate == TypeEntry::GenerateForSubclass ||
+ m_generate == TypeEntry::GenerateNothing) && !m_defaultPackage.isEmpty())
+ TypeDatabase::instance()->addRequiredTargetImport(m_defaultPackage);
+
+ if (!element->entry->qualifiedCppName().isEmpty())
+ m_database->addType(element->entry);
+ break;
+ case StackElement::LoadTypesystem: {
+ QString name = attributes[nameAttribute()];
+ if (name.isEmpty()) {
+ m_error = QLatin1String("No typesystem name specified");
+ return false;
+ }
+ bool generateChild = (convertBoolean(attributes[QLatin1String("generate")], QLatin1String("generate"), true) && (m_generate == TypeEntry::GenerateAll));
+ if (!m_database->parseFile(name, generateChild)) {
+ m_error = QStringLiteral("Failed to parse: '%1'").arg(name);
+ return false;
+ }
+ }
+ break;
+ case StackElement::RejectEnumValue: {
+ if (!m_currentEnum) {
+ m_error = QLatin1String("<reject-enum-value> node must be used inside a <enum-type> node");
+ return false;
+ }
+ QString name = attributes[nameAttribute()];
+ } break;
+ case StackElement::ReplaceType: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Type replacement can only be specified for argument modifications");
+ return false;
+ }
+
+ if (attributes[QLatin1String("modified-type")].isEmpty()) {
+ m_error = QLatin1String("Type replacement requires 'modified-type' attribute");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().modified_type = attributes[QLatin1String("modified-type")];
+ }
+ break;
+ case StackElement::ConversionRule: {
+ if (topElement.type != StackElement::ModifyArgument
+ && topElement.type != StackElement::ValueTypeEntry
+ && topElement.type != StackElement::PrimitiveTypeEntry
+ && topElement.type != StackElement::ContainerTypeEntry) {
+ m_error = QLatin1String("Conversion rules can only be specified for argument modification, "
+ "value-type, primitive-type or container-type conversion.");
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
+ languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
+ }
+
+ QString languageAttribute = attributes[QLatin1String("class")].toLower();
+ TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
+
+ if (topElement.type == StackElement::ModifyArgument) {
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(lang);
+ return false;
+ }
+
+ CodeSnip snip(since);
+ snip.language = lang;
+ m_contextStack.top()->functionMods.last().argument_mods.last().conversion_rules.append(snip);
+ } else {
+ if (topElement.entry->hasConversionRule() || topElement.entry->hasCustomConversion()) {
+ m_error = QLatin1String("Types can have only one conversion rule");
+ return false;
+ }
+
+ // The old conversion rule tag that uses a file containing the conversion
+ // will be kept temporarily for compatibility reasons.
+ QString sourceFile = attributes[QLatin1String("file")];
+ if (!sourceFile.isEmpty()) {
+ if (m_generate != TypeEntry::GenerateForSubclass
+ && m_generate != TypeEntry::GenerateNothing) {
+
+ const char* conversionFlag = NATIVE_CONVERSION_RULE_FLAG;
+ if (lang == TypeSystem::TargetLangCode)
+ conversionFlag = TARGET_CONVERSION_RULE_FLAG;
+
+ QFile conversionSource(sourceFile);
+ if (conversionSource.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ topElement.entry->setConversionRule(QLatin1String(conversionFlag) + QString::fromUtf8(conversionSource.readAll()));
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "File containing conversion code for "
+ << topElement.entry->name() << " type does not exist or is not readable: "
+ << sourceFile;
+ }
+ }
+ }
+
+ CustomConversion* customConversion = new CustomConversion(static_cast<TypeEntry*>(m_current->entry));
+ customConversionsForReview.append(customConversion);
+ }
+ }
+ break;
+ case StackElement::NativeToTarget: {
+ if (topElement.type != StackElement::ConversionRule) {
+ m_error = QLatin1String("Native to Target conversion code can only be specified for custom conversion rules.");
+ return false;
+ }
+ m_contextStack.top()->codeSnips << CodeSnip(0);
+ }
+ break;
+ case StackElement::TargetToNative: {
+ if (topElement.type != StackElement::ConversionRule) {
+ m_error = QLatin1String("Target to Native conversions can only be specified for custom conversion rules.");
+ return false;
+ }
+ bool replace = attributes[QLatin1String("replace")] == QLatin1String("yes");
+ static_cast<TypeEntry*>(m_current->entry)->customConversion()->setReplaceOriginalTargetToNativeConversions(replace);
+ }
+ break;
+ case StackElement::AddConversion: {
+ if (topElement.type != StackElement::TargetToNative) {
+ m_error = QLatin1String("Target to Native conversions can only be added inside 'target-to-native' tags.");
+ return false;
+ }
+ QString sourceTypeName = attributes[QLatin1String("type")];
+ if (sourceTypeName.isEmpty()) {
+ m_error = QLatin1String("Target to Native conversions must specify the input type with the 'type' attribute.");
+ return false;
+ }
+ QString typeCheck = attributes[QLatin1String("check")];
+ static_cast<TypeEntry*>(m_current->entry)->customConversion()->addTargetToNativeConversion(sourceTypeName, typeCheck);
+ m_contextStack.top()->codeSnips << CodeSnip(0);
+ }
+ break;
+ case StackElement::ModifyArgument: {
+ if (topElement.type != StackElement::ModifyFunction
+ && topElement.type != StackElement::AddFunction) {
+ m_error = QString::fromLatin1("argument modification requires function"
+ " modification as parent, was %1")
+ .arg(topElement.type, 0, 16);
+ return false;
+ }
+
+ QString index = attributes[QLatin1String("index")];
+ if (index == QLatin1String("return"))
+ index = QLatin1String("0");
+ else if (index == QLatin1String("this"))
+ index = QLatin1String("-1");
+
+ bool ok = false;
+ int idx = index.toInt(&ok);
+ if (!ok) {
+ m_error = QStringLiteral("Cannot convert '%1' to integer").arg(index);
+ return false;
+ }
+
+ QString replace_value = attributes[QLatin1String("replace-value")];
+
+ if (!replace_value.isEmpty() && idx) {
+ m_error = QLatin1String("replace-value is only supported for return values (index=0).");
+ return false;
+ }
+
+ ArgumentModification argumentModification = ArgumentModification(idx, since);
+ argumentModification.replace_value = replace_value;
+ argumentModification.resetAfterUse = convertBoolean(attributes[QLatin1String("invalidate-after-use")], QLatin1String("invalidate-after-use"), false);
+ m_contextStack.top()->functionMods.last().argument_mods.append(argumentModification);
+ }
+ break;
+ case StackElement::NoNullPointers: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("no-null-pointer requires argument modification as parent");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().noNullPointers = true;
+ if (!m_contextStack.top()->functionMods.last().argument_mods.last().index)
+ m_contextStack.top()->functionMods.last().argument_mods.last().nullPointerDefaultValue = attributes[QLatin1String("default-value")];
+ else if (!attributes[QLatin1String("default-value")].isEmpty())
+ qCWarning(lcShiboken) << "default values for null pointer guards are only effective for return values";
+
+ }
+ break;
+ case StackElement::DefineOwnership: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("define-ownership requires argument modification as parent");
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode;
+ languageNames[QLatin1String("native")] = TypeSystem::NativeCode;
+ }
+
+ QString classAttribute = attributes[QLatin1String("class")].toLower();
+ TypeSystem::Language lang = languageNames.value(classAttribute, TypeSystem::NoLanguage);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(classAttribute);
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Ownership> ownershipNames;
+ if (ownershipNames.isEmpty()) {
+ ownershipNames[QLatin1String("target")] = TypeSystem::TargetLangOwnership;
+ ownershipNames[QLatin1String("c++")] = TypeSystem::CppOwnership;
+ ownershipNames[QLatin1String("default")] = TypeSystem::DefaultOwnership;
+ }
+
+ QString ownershipAttribute = attributes[QLatin1String("owner")].toLower();
+ TypeSystem::Ownership owner = ownershipNames.value(ownershipAttribute, TypeSystem::InvalidOwnership);
+ if (owner == TypeSystem::InvalidOwnership) {
+ m_error = QStringLiteral("unsupported owner attribute: '%1'").arg(ownershipAttribute);
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().ownerships[lang] = owner;
+ }
+ break;
+ case StackElement::SuppressedWarning:
+ if (attributes[QLatin1String("text")].isEmpty())
+ qCWarning(lcShiboken) << "Suppressed warning with no text specified";
+ else
+ m_database->addSuppressedWarning(attributes[QLatin1String("text")]);
+ break;
+ case StackElement::ArgumentMap: {
+ if (!(topElement.type & StackElement::CodeSnipMask)) {
+ m_error = QLatin1String("Argument maps requires code injection as parent");
+ return false;
+ }
+
+ bool ok;
+ int pos = attributes[QLatin1String("index")].toInt(&ok);
+ if (!ok) {
+ m_error = QStringLiteral("Can't convert position '%1' to integer")
+ .arg(attributes[QLatin1String("position")]);
+ return false;
+ }
+
+ if (pos <= 0) {
+ m_error = QStringLiteral("Argument position %1 must be a positive number").arg(pos);
+ return false;
+ }
+
+ QString meta_name = attributes[QLatin1String("meta-name")];
+ if (meta_name.isEmpty())
+ qCWarning(lcShiboken) << "Empty meta name in argument map";
+
+
+ if (topElement.type == StackElement::InjectCodeInFunction)
+ m_contextStack.top()->functionMods.last().snips.last().argumentMap[pos] = meta_name;
+ else {
+ qCWarning(lcShiboken) << "Argument maps are only useful for injection of code "
+ "into functions.";
+ }
+ }
+ break;
+ case StackElement::Removal: {
+ if (topElement.type != StackElement::ModifyFunction) {
+ m_error = QLatin1String("Function modification parent required");
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames.insert(QLatin1String("target"), TypeSystem::TargetLangAndNativeCode);
+ languageNames.insert(QLatin1String("all"), TypeSystem::All);
+ }
+
+ QString languageAttribute = attributes[QLatin1String("class")].toLower();
+ TypeSystem::Language lang = languageNames.value(languageAttribute, TypeSystem::NoLanguage);
+ if (lang == TypeSystem::NoLanguage) {
+ m_error = QStringLiteral("unsupported class attribute: '%1'").arg(languageAttribute);
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().removal = lang;
+ }
+ break;
+ case StackElement::Rename:
+ case StackElement::Access: {
+ if (topElement.type != StackElement::ModifyField
+ && topElement.type != StackElement::ModifyFunction
+ && topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Function, field or argument modification parent required");
+ return false;
+ }
+
+ Modification *mod = 0;
+ if (topElement.type == StackElement::ModifyFunction)
+ mod = &m_contextStack.top()->functionMods.last();
+ else if (topElement.type == StackElement::ModifyField)
+ mod = &m_contextStack.top()->fieldMods.last();
+
+ QString modifier;
+ if (element->type == StackElement::Rename) {
+ modifier = QLatin1String("rename");
+ QString renamed_to = attributes[QLatin1String("to")];
+ if (renamed_to.isEmpty()) {
+ m_error = QLatin1String("Rename modifier requires 'to' attribute");
+ return false;
+ }
+
+ if (topElement.type == StackElement::ModifyFunction)
+ mod->setRenamedTo(renamed_to);
+ else if (topElement.type == StackElement::ModifyField)
+ mod->setRenamedTo(renamed_to);
+ else
+ m_contextStack.top()->functionMods.last().argument_mods.last().renamed_to = renamed_to;
+ } else
+ modifier = attributes[QLatin1String("modifier")].toLower();
+
+
+ if (modifier.isEmpty()) {
+ m_error = QLatin1String("No access modification specified");
+ return false;
+ }
+
+ static QHash<QString, FunctionModification::Modifiers> modifierNames;
+ if (modifierNames.isEmpty()) {
+ modifierNames[QLatin1String("private")] = Modification::Private;
+ modifierNames[QLatin1String("public")] = Modification::Public;
+ modifierNames[QLatin1String("protected")] = Modification::Protected;
+ modifierNames[QLatin1String("friendly")] = Modification::Friendly;
+ modifierNames[QLatin1String("rename")] = Modification::Rename;
+ modifierNames[QLatin1String("final")] = Modification::Final;
+ modifierNames[QLatin1String("non-final")] = Modification::NonFinal;
+ }
+
+ if (!modifierNames.contains(modifier)) {
+ m_error = QStringLiteral("Unknown access modifier: '%1'").arg(modifier);
+ return false;
+ }
+
+ if (mod)
+ mod->modifiers |= modifierNames[modifier];
+ }
+ break;
+ case StackElement::RemoveArgument:
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("Removing argument requires argument modification as parent");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().removed = true;
+ break;
+
+ case StackElement::ModifyField: {
+ QString name = attributes[nameAttribute()];
+ if (name.isEmpty())
+ break;
+ FieldModification fm;
+ fm.name = name;
+ fm.modifiers = 0;
+
+ if (!convertRemovalAttribute(attributes[QLatin1String("remove")], fm, m_error))
+ return false;
+
+ QString read = attributes[QLatin1String("read")];
+ QString write = attributes[QLatin1String("write")];
+
+ if (read == QLatin1String("true")) fm.modifiers |= FieldModification::Readable;
+ if (write == QLatin1String("true")) fm.modifiers |= FieldModification::Writable;
+
+ m_contextStack.top()->fieldMods << fm;
+ }
+ break;
+ case StackElement::AddFunction: {
+ if (!(topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::Root))) {
+ m_error = QString::fromLatin1("Add function requires a complex type or a root tag as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+ QString signature = attributes[QLatin1String("signature")];
+
+ signature = TypeDatabase::normalizedSignature(signature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for the added function");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, QLatin1String("add-function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ AddedFunction func(signature, attributes[QLatin1String("return-type")], since);
+ func.setStatic(attributes[QLatin1String("static")] == QLatin1String("yes"));
+ if (!signature.contains(QLatin1Char('(')))
+ signature += QLatin1String("()");
+ m_currentSignature = signature;
+
+ QString access = attributes[QLatin1String("access")].toLower();
+ if (!access.isEmpty()) {
+ if (access == QLatin1String("protected")) {
+ func.setAccess(AddedFunction::Protected);
+ } else if (access == QLatin1String("public")) {
+ func.setAccess(AddedFunction::Public);
+ } else {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ }
+
+ m_contextStack.top()->addedFunctions << func;
+
+ FunctionModification mod(since);
+ mod.signature = m_currentSignature;
+ m_contextStack.top()->functionMods << mod;
+ }
+ break;
+ case StackElement::ModifyFunction: {
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)) {
+ m_error = QString::fromLatin1("Modify function requires complex type as parent"
+ ", was=%1").arg(topElement.type, 0, 16);
+ return false;
+ }
+ QString signature = attributes[QLatin1String("signature")];
+
+ signature = TypeDatabase::normalizedSignature(signature);
+ if (signature.isEmpty()) {
+ m_error = QLatin1String("No signature for modified function");
+ return false;
+ }
+
+ QString errorString = checkSignatureError(signature, QLatin1String("modify-function"));
+ if (!errorString.isEmpty()) {
+ m_error = errorString;
+ return false;
+ }
+
+ FunctionModification mod(since);
+ m_currentSignature = mod.signature = signature;
+
+ QString access = attributes[QLatin1String("access")].toLower();
+ if (!access.isEmpty()) {
+ if (access == QLatin1String("private"))
+ mod.modifiers |= Modification::Private;
+ else if (access == QLatin1String("protected"))
+ mod.modifiers |= Modification::Protected;
+ else if (access == QLatin1String("public"))
+ mod.modifiers |= Modification::Public;
+ else if (access == QLatin1String("final"))
+ mod.modifiers |= Modification::Final;
+ else if (access == QLatin1String("non-final"))
+ mod.modifiers |= Modification::NonFinal;
+ else {
+ m_error = QString::fromLatin1("Bad access type '%1'").arg(access);
+ return false;
+ }
+ }
+
+ if (convertBoolean(attributes[QLatin1String("deprecated")], QLatin1String("deprecated"), false))
+ mod.modifiers |= Modification::Deprecated;
+
+ if (!convertRemovalAttribute(attributes[QLatin1String("remove")], mod, m_error))
+ return false;
+
+ QString rename = attributes[QLatin1String("rename")];
+ if (!rename.isEmpty()) {
+ mod.renamedToName = rename;
+ mod.modifiers |= Modification::Rename;
+ }
+
+ QString association = attributes[QLatin1String("associated-to")];
+ if (!association.isEmpty())
+ mod.association = association;
+
+ mod.setIsThread(convertBoolean(attributes[QLatin1String("thread")], QLatin1String("thread"), false));
+ mod.setAllowThread(convertBoolean(attributes[QLatin1String("allow-thread")], QLatin1String("allow-thread"), false));
+
+ mod.modifiers |= (convertBoolean(attributes[QLatin1String("virtual-slot")], QLatin1String("virtual-slot"), false) ? Modification::VirtualSlot : 0);
+
+ m_contextStack.top()->functionMods << mod;
+ }
+ break;
+ case StackElement::ReplaceDefaultExpression:
+ if (!(topElement.type & StackElement::ModifyArgument)) {
+ m_error = QLatin1String("Replace default expression only allowed as child of argument modification");
+ return false;
+ }
+
+ if (attributes[QLatin1String("with")].isEmpty()) {
+ m_error = QLatin1String("Default expression replaced with empty string. Use remove-default-expression instead.");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().replacedDefaultExpression = attributes[QLatin1String("with")];
+ break;
+ case StackElement::RemoveDefaultExpression:
+ m_contextStack.top()->functionMods.last().argument_mods.last().removedDefaultExpression = true;
+ break;
+ case StackElement::CustomMetaConstructor:
+ case StackElement::CustomMetaDestructor: {
+ CustomFunction *func = new CustomFunction(attributes[nameAttribute()]);
+ func->paramName = attributes[QLatin1String("param-name")];
+ element->value.customFunction = func;
+ }
+ break;
+ case StackElement::ReferenceCount: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("reference-count must be child of modify-argument");
+ return false;
+ }
+
+ ReferenceCount rc;
+
+ static QHash<QString, ReferenceCount::Action> actions;
+ if (actions.isEmpty()) {
+ actions[QLatin1String("add")] = ReferenceCount::Add;
+ actions[QLatin1String("add-all")] = ReferenceCount::AddAll;
+ actions[QLatin1String("remove")] = ReferenceCount::Remove;
+ actions[QLatin1String("set")] = ReferenceCount::Set;
+ actions[QLatin1String("ignore")] = ReferenceCount::Ignore;
+ }
+ rc.action = actions.value(attributes[QLatin1String("action")].toLower(), ReferenceCount::Invalid);
+ rc.varName = attributes[QLatin1String("variable-name")];
+
+ if (rc.action == ReferenceCount::Invalid) {
+ m_error = QLatin1String("unrecognized value for action attribute. supported actions:");
+ for (QHash<QString, ReferenceCount::Action>::const_iterator it = actions.cbegin(), end = actions.cend(); it != end; ++it)
+ m_error += QLatin1Char(' ') + it.key();
+ }
+
+ m_contextStack.top()->functionMods.last().argument_mods.last().referenceCounts.append(rc);
+ }
+ break;
+
+ case StackElement::ParentOwner: {
+ if (topElement.type != StackElement::ModifyArgument) {
+ m_error = QLatin1String("parent-policy must be child of modify-argument");
+ return false;
+ }
+
+ ArgumentOwner ao;
+
+ QString index = attributes[QLatin1String("index")];
+ if (index == QLatin1String("return"))
+ index = QLatin1String("0");
+ else if (index == QLatin1String("this"))
+ index = QLatin1String("-1");
+
+ bool ok = false;
+ int idx = index.toInt(&ok);
+ if (!ok) {
+ m_error = QStringLiteral("Cannot convert '%1' to integer").arg(index);
+ return false;
+ }
+
+ static QHash<QString, ArgumentOwner::Action> actions;
+ if (actions.isEmpty()) {
+ actions[QLatin1String("add")] = ArgumentOwner::Add;
+ actions[QLatin1String("remove")] = ArgumentOwner::Remove;
+ }
+
+ ao.action = actions.value(attributes[QLatin1String("action")].toLower(), ArgumentOwner::Invalid);
+ if (!ao.action) {
+ m_error = QLatin1String("Invalid parent actionr");
+ return false;
+ }
+ ao.index = idx;
+ m_contextStack.top()->functionMods.last().argument_mods.last().owner = ao;
+ }
+ break;
+
+
+ case StackElement::InjectCode: {
+ if (!(topElement.type & StackElement::ComplexTypeEntryMask)
+ && (topElement.type != StackElement::AddFunction)
+ && (topElement.type != StackElement::ModifyFunction)
+ && (topElement.type != StackElement::Root)) {
+ m_error = QLatin1String("wrong parent type for code injection");
+ return false;
+ }
+
+ static QHash<QString, TypeSystem::Language> languageNames;
+ if (languageNames.isEmpty()) {
+ languageNames[QLatin1String("target")] = TypeSystem::TargetLangCode; // em algum lugar do cpp
+ languageNames[QLatin1String("native")] = TypeSystem::NativeCode; // em algum lugar do cpp
+ languageNames[QLatin1String("shell")] = TypeSystem::ShellCode; // coloca no header, mas antes da declaracao da classe
+ languageNames[QLatin1String("shell-declaration")] = TypeSystem::ShellDeclaration; // coloca no header, dentro da declaracao da classe
+ languageNames[QLatin1String("library-initializer")] = TypeSystem::PackageInitializer;
+ languageNames[QLatin1String("destructor-function")] = TypeSystem::DestructorFunction;
+ languageNames[QLatin1String("constructors")] = TypeSystem::Constructors;
+ languageNames[QLatin1String("interface")] = TypeSystem::Interface;
+ }
+
+ QString className = attributes[QLatin1String("class")].toLower();
+ if (!languageNames.contains(className)) {
+ m_error = QStringLiteral("Invalid class specifier: '%1'").arg(className);
+ return false;
+ }
+
+
+ static QHash<QString, TypeSystem::CodeSnipPosition> positionNames;
+ if (positionNames.isEmpty()) {
+ positionNames.insert(QLatin1String("beginning"), TypeSystem::CodeSnipPositionBeginning);
+ positionNames.insert(QLatin1String("end"), TypeSystem::CodeSnipPositionEnd);
+ // QtScript
+ positionNames.insert(QLatin1String("declaration"), TypeSystem::CodeSnipPositionDeclaration);
+ positionNames.insert(QLatin1String("prototype-initialization"), TypeSystem::CodeSnipPositionPrototypeInitialization);
+ positionNames.insert(QLatin1String("constructor-initialization"), TypeSystem::CodeSnipPositionConstructorInitialization);
+ positionNames.insert(QLatin1String("constructor"), TypeSystem::CodeSnipPositionConstructor);
+ }
+
+ QString position = attributes[QLatin1String("position")].toLower();
+ if (!positionNames.contains(position)) {
+ m_error = QStringLiteral("Invalid position: '%1'").arg(position);
+ return false;
+ }
+
+ CodeSnip snip(since);
+ snip.language = languageNames[className];
+ snip.position = positionNames[position];
+ bool in_file = false;
+
+ QString file_name = attributes[QLatin1String("file")];
+
+ //Handler constructor....
+ if (m_generate != TypeEntry::GenerateForSubclass &&
+ m_generate != TypeEntry::GenerateNothing &&
+ !file_name.isEmpty()) {
+ if (QFile::exists(file_name)) {
+ QFile codeFile(file_name);
+ if (codeFile.open(QIODevice::Text | QIODevice::ReadOnly)) {
+ QString content = QLatin1String("// ========================================================================\n"
+ "// START of custom code block [file: ");
+ content += file_name;
+ content += QLatin1String("]\n");
+ content += QString::fromUtf8(codeFile.readAll());
+ content += QLatin1String("\n// END of custom code block [file: ");
+ content += file_name;
+ content += QLatin1String("]\n// ========================================================================\n");
+ snip.addCode(content);
+ in_file = true;
+ }
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "File for inject code not exist: " << QDir::toNativeSeparators(file_name);
+ }
+
+ }
+
+ if (snip.language == TypeSystem::Interface && topElement.type != StackElement::InterfaceTypeEntry) {
+ m_error = QLatin1String("Interface code injections must be direct child of an interface type entry");
+ return false;
+ }
+
+ if (topElement.type == StackElement::ModifyFunction || topElement.type == StackElement::AddFunction) {
+ FunctionModification mod = m_contextStack.top()->functionMods.last();
+ if (snip.language == TypeSystem::ShellDeclaration) {
+ m_error = QLatin1String("no function implementation in shell declaration in which to inject code");
+ return false;
+ }
+
+ m_contextStack.top()->functionMods.last().snips << snip;
+ if (in_file)
+ m_contextStack.top()->functionMods.last().modifiers |= FunctionModification::CodeInjection;
+ element->type = StackElement::InjectCodeInFunction;
+ } else if (topElement.type == StackElement::Root) {
+ element->entry->addCodeSnip(snip);
+ } else if (topElement.type != StackElement::Root) {
+ m_contextStack.top()->codeSnips << snip;
+ }
+
+ }
+ break;
+ case StackElement::Include: {
+ QString location = attributes[QLatin1String("location")].toLower();
+
+ static QHash<QString, Include::IncludeType> locationNames;
+ if (locationNames.isEmpty()) {
+ locationNames[QLatin1String("global")] = Include::IncludePath;
+ locationNames[QLatin1String("local")] = Include::LocalPath;
+ locationNames[QLatin1String("target")] = Include::TargetLangImport;
+ }
+
+ if (!locationNames.contains(location)) {
+ m_error = QStringLiteral("Location not recognized: '%1'").arg(location);
+ return false;
+ }
+
+ Include::IncludeType loc = locationNames[location];
+ Include inc(loc, attributes[QLatin1String("file-name")]);
+
+ ComplexTypeEntry *ctype = static_cast<ComplexTypeEntry *>(element->entry);
+ if (topElement.type & (StackElement::ComplexTypeEntryMask | StackElement::PrimitiveTypeEntry)) {
+ element->entry->setInclude(inc);
+ } else if (topElement.type == StackElement::ExtraIncludes) {
+ element->entry->addExtraInclude(inc);
+ } else {
+ m_error = QLatin1String("Only supported parent tags are primitive-type, complex types or extra-includes");
+ return false;
+ }
+
+ inc = ctype->include();
+ IncludeList lst = ctype->extraIncludes();
+ ctype = ctype->designatedInterface();
+ if (ctype) {
+ ctype->setExtraIncludes(lst);
+ ctype->setInclude(inc);
+ }
+ }
+ break;
+ case StackElement::Rejection:
+ if (!addRejection(m_database, attributes, &m_error))
+ return false;
+ break;
+ case StackElement::Template:
+ element->value.templateEntry = new TemplateEntry(attributes[nameAttribute()], since);
+ break;
+ case StackElement::TemplateInstanceEnum:
+ if (!(topElement.type & StackElement::CodeSnipMask) &&
+ (topElement.type != StackElement::Template) &&
+ (topElement.type != StackElement::CustomMetaConstructor) &&
+ (topElement.type != StackElement::CustomMetaDestructor) &&
+ (topElement.type != StackElement::NativeToTarget) &&
+ (topElement.type != StackElement::AddConversion) &&
+ (topElement.type != StackElement::ConversionRule)) {
+ m_error = QLatin1String("Can only insert templates into code snippets, templates, custom-constructors, "\
+ "custom-destructors, conversion-rule, native-to-target or add-conversion tags.");
+ return false;
+ }
+ element->value.templateInstance = new TemplateInstance(attributes[nameAttribute()], since);
+ break;
+ case StackElement::Replace:
+ if (topElement.type != StackElement::TemplateInstanceEnum) {
+ m_error = QLatin1String("Can only insert replace rules into insert-template.");
+ return false;
+ }
+ element->parent->value.templateInstance->addReplaceRule(attributes[QLatin1String("from")], attributes[QLatin1String("to")]);
+ break;
+ default:
+ break; // nada
+ };
+ }
+
+ m_current = element;
+ return true;
+}
+
+PrimitiveTypeEntry *PrimitiveTypeEntry::basicReferencedTypeEntry() const
+{
+ if (!m_referencedTypeEntry)
+ return 0;
+
+ PrimitiveTypeEntry *baseReferencedTypeEntry = m_referencedTypeEntry->basicReferencedTypeEntry();
+ if (baseReferencedTypeEntry)
+ return baseReferencedTypeEntry;
+ else
+ return m_referencedTypeEntry;
+}
+
+typedef QHash<const PrimitiveTypeEntry*, QString> PrimitiveTypeEntryTargetLangPackageMap;
+Q_GLOBAL_STATIC(PrimitiveTypeEntryTargetLangPackageMap, primitiveTypeEntryTargetLangPackages);
+
+void PrimitiveTypeEntry::setTargetLangPackage(const QString& package)
+{
+ primitiveTypeEntryTargetLangPackages()->insert(this, package);
+}
+QString PrimitiveTypeEntry::targetLangPackage() const
+{
+ if (!primitiveTypeEntryTargetLangPackages()->contains(this))
+ return this->::TypeEntry::targetLangPackage();
+ return primitiveTypeEntryTargetLangPackages()->value(this);
+}
+
+CodeSnipList TypeEntry::codeSnips() const
+{
+ return m_codeSnips;
+}
+
+QString Modification::accessModifierString() const
+{
+ if (isPrivate()) return QLatin1String("private");
+ if (isProtected()) return QLatin1String("protected");
+ if (isPublic()) return QLatin1String("public");
+ if (isFriendly()) return QLatin1String("friendly");
+ return QString();
+}
+
+FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const
+{
+ FunctionModificationList lst;
+ for (int i = 0; i < m_functionMods.count(); ++i) {
+ const FunctionModification &mod = m_functionMods.at(i);
+ if (mod.signature == signature)
+ lst << mod;
+ }
+ return lst;
+}
+
+FieldModification ComplexTypeEntry::fieldModification(const QString &name) const
+{
+ for (int i = 0; i < m_fieldMods.size(); ++i)
+ if (m_fieldMods.at(i).name == name)
+ return m_fieldMods.at(i);
+ FieldModification mod;
+ mod.name = name;
+ mod.modifiers = FieldModification::Readable | FieldModification::Writable;
+ return mod;
+}
+
+// The things we do not to break the ABI...
+typedef QHash<const ComplexTypeEntry*, QString> ComplexTypeEntryDefaultConstructorMap;
+Q_GLOBAL_STATIC(ComplexTypeEntryDefaultConstructorMap, complexTypeEntryDefaultConstructors);
+
+void ComplexTypeEntry::setDefaultConstructor(const QString& defaultConstructor)
+{
+ if (!defaultConstructor.isEmpty())
+ complexTypeEntryDefaultConstructors()->insert(this, defaultConstructor);
+}
+QString ComplexTypeEntry::defaultConstructor() const
+{
+ if (!complexTypeEntryDefaultConstructors()->contains(this))
+ return QString();
+ return complexTypeEntryDefaultConstructors()->value(this);
+}
+bool ComplexTypeEntry::hasDefaultConstructor() const
+{
+ return complexTypeEntryDefaultConstructors()->contains(this);
+}
+
+QString ContainerTypeEntry::targetLangPackage() const
+{
+ return QString();
+}
+
+QString ContainerTypeEntry::targetLangName() const
+{
+
+ switch (m_type) {
+ case StringListContainer: return QLatin1String("QStringList");
+ case ListContainer: return QLatin1String("QList");
+ case LinkedListContainer: return QLatin1String("QLinkedList");
+ case VectorContainer: return QLatin1String("QVector");
+ case StackContainer: return QLatin1String("QStack");
+ case QueueContainer: return QLatin1String("QQueue");
+ case SetContainer: return QLatin1String("QSet");
+ case MapContainer: return QLatin1String("QMap");
+ case MultiMapContainer: return QLatin1String("QMultiMap");
+ case HashContainer: return QLatin1String("QHash");
+ case MultiHashContainer: return QLatin1String("QMultiHash");
+ case PairContainer: return QLatin1String("QPair");
+ default:
+ qWarning("bad type... %d", m_type);
+ break;
+ }
+ return QString();
+}
+
+QString ContainerTypeEntry::qualifiedCppName() const
+{
+ if (m_type == StringListContainer)
+ return QLatin1String("QStringList");
+ return ComplexTypeEntry::qualifiedCppName();
+}
+
+QString EnumTypeEntry::targetLangQualifier() const
+{
+ TypeEntry *te = TypeDatabase::instance()->findType(m_qualifier);
+ if (te)
+ return te->targetLangName();
+ else
+ return m_qualifier;
+}
+
+QString EnumTypeEntry::targetLangApiName() const
+{
+ return QLatin1String("jint");
+}
+
+QString FlagsTypeEntry::targetLangApiName() const
+{
+ return QLatin1String("jint");
+}
+
+void EnumTypeEntry::addEnumValueRedirection(const QString &rejected, const QString &usedValue)
+{
+ m_enumRedirections << EnumValueRedirection(rejected, usedValue);
+}
+
+QString EnumTypeEntry::enumValueRedirection(const QString &value) const
+{
+ for (int i = 0; i < m_enumRedirections.size(); ++i)
+ if (m_enumRedirections.at(i).rejected == value)
+ return m_enumRedirections.at(i).used;
+ return QString();
+}
+
+QString FlagsTypeEntry::qualifiedTargetLangName() const
+{
+ return targetLangPackage() + QLatin1Char('.') + m_enum->targetLangQualifier()
+ + QLatin1Char('.') + targetLangName();
+}
+
+/*!
+ * The Visual Studio 2002 compiler doesn't support these symbols,
+ * which our typedefs unforntuatly expand to.
+ */
+QString fixCppTypeName(const QString &name)
+{
+ if (name == QLatin1String("long long"))
+ return QLatin1String("qint64");
+ else if (name == QLatin1String("unsigned long long"))
+ return QLatin1String("quint64");
+ return name;
+}
+
+QString TemplateInstance::expandCode() const
+{
+ TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name);
+ if (templateEntry) {
+ typedef QHash<QString, QString>::const_iterator ConstIt;
+ QString code = templateEntry->code();
+ for (ConstIt it = replaceRules.begin(), end = replaceRules.end(); it != end; ++it)
+ code.replace(it.key(), it.value());
+ while (!code.isEmpty() && code.at(code.size() - 1).isSpace())
+ code.chop(1);
+ QString result = QLatin1String("// TEMPLATE - ") + m_name + QLatin1String(" - START");
+ if (!code.startsWith(QLatin1Char('\n')))
+ result += QLatin1Char('\n');
+ result += code;
+ result += QLatin1String("\n// TEMPLATE - ") + m_name + QLatin1String(" - END");
+ return result;
+ } else {
+ qCWarning(lcShiboken).noquote().nospace()
+ << "insert-template referring to non-existing template '" << m_name << '\'';
+ }
+
+ return QString();
+}
+
+
+QString CodeSnipAbstract::code() const
+{
+ QString res;
+ for (const CodeSnipFragment &codeFrag : codeList)
+ res.append(codeFrag.code());
+
+ return res;
+}
+
+QString CodeSnipFragment::code() const
+{
+ if (m_instance)
+ return m_instance->expandCode();
+ else
+ return m_code;
+}
+
+QString FunctionModification::toString() const
+{
+ QString str = signature + QLatin1String("->");
+ if (modifiers & AccessModifierMask) {
+ switch (modifiers & AccessModifierMask) {
+ case Private: str += QLatin1String("private"); break;
+ case Protected: str += QLatin1String("protected"); break;
+ case Public: str += QLatin1String("public"); break;
+ case Friendly: str += QLatin1String("friendly"); break;
+ }
+ }
+
+ if (modifiers & Final) str += QLatin1String("final");
+ if (modifiers & NonFinal) str += QLatin1String("non-final");
+
+ if (modifiers & Readable) str += QLatin1String("readable");
+ if (modifiers & Writable) str += QLatin1String("writable");
+
+ if (modifiers & CodeInjection) {
+ for (const CodeSnip &s : snips) {
+ str += QLatin1String("\n//code injection:\n");
+ str += s.code();
+ }
+ }
+
+ if (modifiers & Rename) str += QLatin1String("renamed:") + renamedToName;
+
+ if (modifiers & Deprecated) str += QLatin1String("deprecate");
+
+ if (modifiers & ReplaceExpression) str += QLatin1String("replace-expression");
+
+ return str;
+}
+
+bool FunctionModification::operator!=(const FunctionModification& other) const
+{
+ return !(*this == other);
+}
+
+bool FunctionModification::operator==(const FunctionModification& other) const
+{
+ if (signature != other.signature)
+ return false;
+
+ if (association != other.association)
+ return false;
+
+ if (modifiers != other.modifiers)
+ return false;
+
+ if (removal != other.removal)
+ return false;
+
+ if (m_thread != other.m_thread)
+ return false;
+
+ if (m_allowThread != other.m_allowThread)
+ return false;
+
+ if (m_version != other.m_version)
+ return false;
+
+ return true;
+}
+
+static AddedFunction::TypeInfo parseType(const QString& signature, int startPos = 0, int* endPos = 0)
+{
+ AddedFunction::TypeInfo result;
+ static const QRegularExpression regex(QLatin1String("\\w"));
+ Q_ASSERT(regex.isValid());
+ int length = signature.length();
+ int start = signature.indexOf(regex, startPos);
+ if (start == -1) {
+ if (signature.midRef(startPos + 1, 3) == QLatin1String("...")) { // varargs
+ if (endPos)
+ *endPos = startPos + 4;
+ result.name = QLatin1String("...");
+ } else { // error
+ if (endPos)
+ *endPos = length;
+ }
+ return result;
+ }
+
+ int cantStop = 0;
+ QString paramString;
+ QChar c;
+ int i = start;
+ for (; i < length; ++i) {
+ c = signature[i];
+ if (c == QLatin1Char('<'))
+ cantStop++;
+ if (c == QLatin1Char('>'))
+ cantStop--;
+ if (cantStop < 0)
+ break; // FIXME: report error?
+ if ((c == QLatin1Char(')') || c == QLatin1Char(',')) && !cantStop)
+ break;
+ paramString += signature[i];
+ }
+ if (endPos)
+ *endPos = i;
+
+ // Check default value
+ if (paramString.contains(QLatin1Char('='))) {
+ QStringList lst = paramString.split(QLatin1Char('='));
+ paramString = lst[0].trimmed();
+ result.defaultValue = lst[1].trimmed();
+ }
+
+ // check constness
+ if (paramString.startsWith(QLatin1String("const "))) {
+ result.isConstant = true;
+ paramString.remove(0, sizeof("const")/sizeof(char));
+ paramString = paramString.trimmed();
+ }
+ // check reference
+ if (paramString.endsWith(QLatin1Char('&'))) {
+ result.isReference = true;
+ paramString.chop(1);
+ paramString = paramString.trimmed();
+ }
+ // check Indirections
+ while (paramString.endsWith(QLatin1Char('*'))) {
+ result.indirections++;
+ paramString.chop(1);
+ paramString = paramString.trimmed();
+ }
+ result.name = paramString;
+
+ return result;
+}
+
+AddedFunction::AddedFunction(QString signature, QString returnType, double vr) : m_access(Public), m_version(vr)
+{
+ Q_ASSERT(!returnType.isEmpty());
+ m_returnType = parseType(returnType);
+ signature = signature.trimmed();
+ int endPos = signature.indexOf(QLatin1Char('('));
+ if (endPos < 0) {
+ m_isConst = false;
+ m_name = signature;
+ } else {
+ m_name = signature.left(endPos).trimmed();
+ int signatureLength = signature.length();
+ while (endPos < signatureLength) {
+ TypeInfo arg = parseType(signature, endPos, &endPos);
+ if (!arg.name.isEmpty())
+ m_arguments.append(arg);
+ // end of parameters...
+ if (signature[endPos] == QLatin1Char(')'))
+ break;
+ }
+ // is const?
+ m_isConst = signature.right(signatureLength - endPos).contains(QLatin1String("const"));
+ }
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "TypeInfo(";
+ if (ti.isConstant)
+ d << "const";
+ if (ti.indirections)
+ d << QByteArray(ti.indirections, '*');
+ if (ti.isReference)
+ d << " &";
+ d << ti.name;
+ if (!ti.defaultValue.isEmpty())
+ d << " = " << ti.defaultValue;
+ d << ')';
+ return d;
+}
+
+QDebug operator<<(QDebug d, const AddedFunction &af)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "AddedFunction(";
+ if (af.access() == AddedFunction::Protected)
+ d << "protected";
+ if (af.isStatic())
+ d << " static";
+ d << af.returnType() << ' ' << af.name() << '(' << af.arguments() << ')';
+ if (af.isConstant())
+ d << " const";
+ return d;
+}
+#endif // !QT_NO_DEBUG_STREAM
+
+AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& signature)
+{
+ return parseType(signature);
+}
+
+QString ComplexTypeEntry::targetLangApiName() const
+{
+ return strings_jobject;
+}
+QString StringTypeEntry::targetLangApiName() const
+{
+ return strings_jobject;
+}
+QString StringTypeEntry::targetLangName() const
+{
+ return strings_String;
+}
+QString StringTypeEntry::targetLangPackage() const
+{
+ return QString();
+}
+QString CharTypeEntry::targetLangApiName() const
+{
+ return strings_jchar;
+}
+QString CharTypeEntry::targetLangName() const
+{
+ return strings_char;
+}
+QString VariantTypeEntry::targetLangApiName() const
+{
+ return strings_jobject;
+}
+QString VariantTypeEntry::targetLangName() const
+{
+ return strings_Object;
+}
+QString VariantTypeEntry::targetLangPackage() const
+{
+ return QString();
+}
+
+QString ContainerTypeEntry::typeName() const
+{
+ switch(m_type) {
+ case LinkedListContainer:
+ return QLatin1String("linked-list");
+ case ListContainer:
+ return QLatin1String("list");
+ case StringListContainer:
+ return QLatin1String("string-list");
+ case VectorContainer:
+ return QLatin1String("vector");
+ case StackContainer:
+ return QLatin1String("stack");
+ case QueueContainer:
+ return QLatin1String("queue");
+ case SetContainer:
+ return QLatin1String("set");
+ case MapContainer:
+ return QLatin1String("map");
+ case MultiMapContainer:
+ return QLatin1String("multi-map");
+ case HashContainer:
+ return QLatin1String("hash");
+ case MultiHashContainer:
+ return QLatin1String("multi-hash");
+ case PairContainer:
+ return QLatin1String("pair");
+ case NoContainer:
+ default:
+ return QLatin1String("?");
+ }
+}
+
+static bool strLess(const char* a, const char* b)
+{
+ return ::strcmp(a, b) < 0;
+}
+
+bool TypeEntry::isCppPrimitive() const
+{
+ if (!isPrimitive())
+ return false;
+
+ const PrimitiveTypeEntry *referencedType =
+ static_cast<const PrimitiveTypeEntry *>(this)->basicReferencedTypeEntry();
+ QByteArray typeName = (referencedType ? referencedType->name() : m_name).toUtf8();
+
+ if (typeName.contains(' ') || m_type == VoidType)
+ return true;
+ // Keep this sorted!!
+ static const char* cppTypes[] = { "bool", "char", "double", "float", "int", "long", "long long", "short", "wchar_t" };
+ const int N = sizeof(cppTypes)/sizeof(char*);
+
+ const char** res = qBinaryFind(&cppTypes[0], &cppTypes[N], typeName.constData(), strLess);
+
+ return res != &cppTypes[N];
+}
+
+// Again, stuff to avoid ABI breakage.
+typedef QHash<const TypeEntry*, CustomConversion*> TypeEntryCustomConversionMap;
+Q_GLOBAL_STATIC(TypeEntryCustomConversionMap, typeEntryCustomConversionMap);
+
+TypeEntry::~TypeEntry()
+{
+ if (typeEntryCustomConversionMap()->contains(this)) {
+ CustomConversion* customConversion = typeEntryCustomConversionMap()->value(this);
+ typeEntryCustomConversionMap()->remove(this);
+ delete customConversion;
+ }
+}
+
+bool TypeEntry::hasCustomConversion() const
+{
+ return typeEntryCustomConversionMap()->contains(this);
+}
+void TypeEntry::setCustomConversion(CustomConversion* customConversion)
+{
+ if (customConversion)
+ typeEntryCustomConversionMap()->insert(this, customConversion);
+ else if (typeEntryCustomConversionMap()->contains(this))
+ typeEntryCustomConversionMap()->remove(this);
+}
+CustomConversion* TypeEntry::customConversion() const
+{
+ if (typeEntryCustomConversionMap()->contains(this))
+ return typeEntryCustomConversionMap()->value(this);
+ return 0;
+}
+
+/*
+static void injectCode(ComplexTypeEntry *e,
+ const char *signature,
+ const QByteArray &code,
+ const ArgumentMap &args)
+{
+ CodeSnip snip;
+ snip.language = TypeSystem::NativeCode;
+ snip.position = CodeSnip::Beginning;
+ snip.addCode(QString::fromLatin1(code));
+ snip.argumentMap = args;
+
+ FunctionModification mod;
+ mod.signature = QMetaObject::normalizedSignature(signature);
+ mod.snips << snip;
+ mod.modifiers = Modification::CodeInjection;
+}
+*/
+
+struct CustomConversion::CustomConversionPrivate
+{
+ CustomConversionPrivate(const TypeEntry* ownerType)
+ : ownerType(ownerType), replaceOriginalTargetToNativeConversions(false)
+ {
+ }
+ const TypeEntry* ownerType;
+ QString nativeToTargetConversion;
+ bool replaceOriginalTargetToNativeConversions;
+ TargetToNativeConversions targetToNativeConversions;
+};
+
+struct CustomConversion::TargetToNativeConversion::TargetToNativeConversionPrivate
+{
+ TargetToNativeConversionPrivate()
+ : sourceType(0)
+ {
+ }
+ const TypeEntry* sourceType;
+ QString sourceTypeName;
+ QString sourceTypeCheck;
+ QString conversion;
+};
+
+CustomConversion::CustomConversion(TypeEntry* ownerType)
+{
+ m_d = new CustomConversionPrivate(ownerType);
+ if (ownerType)
+ ownerType->setCustomConversion(this);
+}
+
+CustomConversion::~CustomConversion()
+{
+ qDeleteAll(m_d->targetToNativeConversions);
+ delete m_d;
+}
+
+const TypeEntry* CustomConversion::ownerType() const
+{
+ return m_d->ownerType;
+}
+
+QString CustomConversion::nativeToTargetConversion() const
+{
+ return m_d->nativeToTargetConversion;
+}
+
+void CustomConversion::setNativeToTargetConversion(const QString& nativeToTargetConversion)
+{
+ m_d->nativeToTargetConversion = nativeToTargetConversion;
+}
+
+bool CustomConversion::replaceOriginalTargetToNativeConversions() const
+{
+ return m_d->replaceOriginalTargetToNativeConversions;
+}
+
+void CustomConversion::setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions)
+{
+ m_d->replaceOriginalTargetToNativeConversions = replaceOriginalTargetToNativeConversions;
+}
+
+bool CustomConversion::hasTargetToNativeConversions() const
+{
+ return !(m_d->targetToNativeConversions.isEmpty());
+}
+
+CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions()
+{
+ return m_d->targetToNativeConversions;
+}
+
+const CustomConversion::TargetToNativeConversions& CustomConversion::targetToNativeConversions() const
+{
+ return m_d->targetToNativeConversions;
+}
+
+void CustomConversion::addTargetToNativeConversion(const QString& sourceTypeName,
+ const QString& sourceTypeCheck,
+ const QString& conversion)
+{
+ m_d->targetToNativeConversions.append(new TargetToNativeConversion(sourceTypeName, sourceTypeCheck, conversion));
+}
+
+CustomConversion::TargetToNativeConversion::TargetToNativeConversion(const QString& sourceTypeName,
+ const QString& sourceTypeCheck,
+ const QString& conversion)
+{
+ m_d = new TargetToNativeConversionPrivate;
+ m_d->sourceTypeName = sourceTypeName;
+ m_d->sourceTypeCheck = sourceTypeCheck;
+ m_d->conversion = conversion;
+}
+
+CustomConversion::TargetToNativeConversion::~TargetToNativeConversion()
+{
+ delete m_d;
+}
+
+const TypeEntry* CustomConversion::TargetToNativeConversion::sourceType() const
+{
+ return m_d->sourceType;
+}
+
+void CustomConversion::TargetToNativeConversion::setSourceType(const TypeEntry* sourceType)
+{
+ m_d->sourceType = sourceType;
+}
+
+bool CustomConversion::TargetToNativeConversion::isCustomType() const
+{
+ return !(m_d->sourceType);
+}
+
+QString CustomConversion::TargetToNativeConversion::sourceTypeName() const
+{
+ return m_d->sourceTypeName;
+}
+
+QString CustomConversion::TargetToNativeConversion::sourceTypeCheck() const
+{
+ return m_d->sourceTypeCheck;
+}
+
+QString CustomConversion::TargetToNativeConversion::conversion() const
+{
+ return m_d->conversion;
+}
+
+void CustomConversion::TargetToNativeConversion::setConversion(const QString& conversion)
+{
+ m_d->conversion = conversion;
+}
diff --git a/sources/shiboken2/ApiExtractor/typesystem.h b/sources/shiboken2/ApiExtractor/typesystem.h
new file mode 100644
index 000000000..b75da48ba
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typesystem.h
@@ -0,0 +1,1975 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TYPESYSTEM_H
+#define TYPESYSTEM_H
+
+#include "typesystem_enums.h"
+#include "typesystem_typedefs.h"
+#include "include.h"
+
+#include <QtCore/QHash>
+#include <QtCore/qobjectdefs.h>
+#include <QtCore/QRegularExpression>
+#include <QtCore/QString>
+#include <QtCore/QStringList>
+#include <QtCore/QMap>
+#include <QtCore/QVector>
+
+//Used to identify the conversion rule to avoid break API
+#define TARGET_CONVERSION_RULE_FLAG "0"
+#define NATIVE_CONVERSION_RULE_FLAG "1"
+
+class Indentor;
+
+class AbstractMetaType;
+QT_BEGIN_NAMESPACE
+class QDebug;
+class QTextStream;
+QT_END_NAMESPACE
+
+class EnumTypeEntry;
+class FlagsTypeEntry;
+
+typedef QMap<int, QString> ArgumentMap;
+
+class TemplateInstance;
+
+struct ReferenceCount
+{
+ ReferenceCount() {}
+ enum Action { // 0x01 - 0xff
+ Invalid = 0x00,
+ Add = 0x01,
+ AddAll = 0x02,
+ Remove = 0x04,
+ Set = 0x08,
+ Ignore = 0x10,
+
+ ActionsMask = 0xff,
+
+ Padding = 0xffffffff
+ };
+
+ Action action;
+ QString varName;
+};
+
+struct ArgumentOwner
+{
+ enum Action {
+ Invalid = 0x00,
+ Add = 0x01,
+ Remove = 0x02
+ };
+ enum {
+ InvalidIndex = -2,
+ ThisIndex = -1,
+ ReturnIndex = 0,
+ FirstArgumentIndex = 1
+ };
+ ArgumentOwner() : action(ArgumentOwner::Invalid), index(ArgumentOwner::InvalidIndex) {}
+
+ Action action;
+ int index;
+};
+
+class CodeSnipFragment
+{
+private:
+ QString m_code;
+ TemplateInstance *m_instance;
+
+public:
+ CodeSnipFragment() : m_instance(0) {}
+ CodeSnipFragment(const QString &code)
+ : m_code(code),
+ m_instance(0) {}
+
+ CodeSnipFragment(TemplateInstance *instance)
+ : m_instance(instance) {}
+
+ QString code() const;
+};
+
+class CodeSnipAbstract
+{
+public:
+ QString code() const;
+
+ void addCode(const QString &code) { codeList.append(CodeSnipFragment(code)); }
+ void addCode(const QStringRef &code) { addCode(code.toString()); }
+
+ void addTemplateInstance(TemplateInstance *ti)
+ {
+ codeList.append(CodeSnipFragment(ti));
+ }
+
+ QVector<CodeSnipFragment> codeList;
+};
+
+class CustomFunction : public CodeSnipAbstract
+{
+public:
+ CustomFunction(const QString &n = QString()) : name(n) { }
+
+ QString name;
+ QString paramName;
+};
+
+class TemplateEntry : public CodeSnipAbstract
+{
+public:
+ TemplateEntry(const QString &name, double vr)
+ : m_name(name), m_version(vr)
+ {
+ };
+
+ QString name() const
+ {
+ return m_name;
+ };
+
+ double version() const
+ {
+ return m_version;
+ }
+
+private:
+ QString m_name;
+ double m_version;
+};
+
+class TemplateInstance
+{
+public:
+ TemplateInstance(const QString &name, double vr)
+ : m_name(name), m_version(vr) {}
+
+ void addReplaceRule(const QString &name, const QString &value)
+ {
+ replaceRules[name] = value;
+ }
+
+ QString expandCode() const;
+
+ QString name() const
+ {
+ return m_name;
+ }
+
+ double version() const
+ {
+ return m_version;
+ }
+
+private:
+ const QString m_name;
+ double m_version;
+ QHash<QString, QString> replaceRules;
+};
+
+
+class CodeSnip : public CodeSnipAbstract
+{
+public:
+ CodeSnip() : language(TypeSystem::TargetLangCode), version(0) {}
+ CodeSnip(double vr) : language(TypeSystem::TargetLangCode), version(vr) { }
+ CodeSnip(double vr, TypeSystem::Language lang) : language(lang), version(vr) { }
+
+ TypeSystem::Language language;
+ TypeSystem::CodeSnipPosition position;
+ ArgumentMap argumentMap;
+ double version;
+};
+
+struct ArgumentModification
+{
+ ArgumentModification() : removedDefaultExpression(false), removed(false),
+ noNullPointers(false), index(-1), version(0) {}
+ ArgumentModification(int idx, double vr)
+ : removedDefaultExpression(false), removed(false),
+ noNullPointers(false), index(idx), version(vr) {}
+
+ // Should the default expression be removed?
+ uint removedDefaultExpression : 1;
+ uint removed : 1;
+ uint noNullPointers : 1;
+ uint resetAfterUse : 1;
+
+ // The index of this argument
+ int index;
+
+ // Reference count flags for this argument
+ QVector<ReferenceCount> referenceCounts;
+
+ // The text given for the new type of the argument
+ QString modified_type;
+
+ QString replace_value;
+
+ // The code to be used to construct a return value when noNullPointers is true and
+ // the returned value is null. If noNullPointers is true and this string is
+ // empty, then the base class implementation will be used (or a default construction
+ // if there is no implementation)
+ QString nullPointerDefaultValue;
+
+ // The text of the new default expression of the argument
+ QString replacedDefaultExpression;
+
+ // The new definition of ownership for a specific argument
+ QHash<TypeSystem::Language, TypeSystem::Ownership> ownerships;
+
+ // Different conversion rules
+ CodeSnipList conversion_rules;
+
+ //QObject parent(owner) of this argument
+ ArgumentOwner owner;
+
+ //Api version
+ double version;
+
+ //New name
+ QString renamed_to;
+};
+
+struct Modification
+{
+ enum Modifiers {
+ Private = 0x0001,
+ Protected = 0x0002,
+ Public = 0x0003,
+ Friendly = 0x0004,
+ AccessModifierMask = 0x000f,
+
+ Final = 0x0010,
+ NonFinal = 0x0020,
+ FinalMask = Final | NonFinal,
+
+ Readable = 0x0100,
+ Writable = 0x0200,
+
+ CodeInjection = 0x1000,
+ Rename = 0x2000,
+ Deprecated = 0x4000,
+ ReplaceExpression = 0x8000,
+ VirtualSlot = 0x10000 | NonFinal
+ };
+
+ Modification() : modifiers(0), removal(TypeSystem::NoLanguage) { }
+
+ bool isAccessModifier() const
+ {
+ return modifiers & AccessModifierMask;
+ }
+ Modifiers accessModifier() const
+ {
+ return Modifiers(modifiers & AccessModifierMask);
+ }
+ bool isPrivate() const
+ {
+ return accessModifier() == Private;
+ }
+ bool isProtected() const
+ {
+ return accessModifier() == Protected;
+ }
+ bool isPublic() const
+ {
+ return accessModifier() == Public;
+ }
+ bool isFriendly() const
+ {
+ return accessModifier() == Friendly;
+ }
+ bool isFinal() const
+ {
+ return modifiers & Final;
+ }
+ bool isNonFinal() const
+ {
+ return modifiers & NonFinal;
+ }
+ bool isVirtualSlot() const
+ {
+ return (modifiers & VirtualSlot) == VirtualSlot;
+ }
+ QString accessModifierString() const;
+
+ bool isDeprecated() const
+ {
+ return modifiers & Deprecated;
+ }
+
+ void setRenamedTo(const QString &name)
+ {
+ renamedToName = name;
+ }
+ QString renamedTo() const
+ {
+ return renamedToName;
+ }
+ bool isRenameModifier() const
+ {
+ return modifiers & Rename;
+ }
+
+ bool isRemoveModifier() const
+ {
+ return removal != TypeSystem::NoLanguage;
+ }
+
+ uint modifiers;
+ QString renamedToName;
+ TypeSystem::Language removal;
+};
+
+struct FunctionModification: public Modification
+{
+ FunctionModification() : m_thread(false), m_allowThread(false), m_version(0) {}
+ FunctionModification(double vr) : m_thread(false), m_allowThread(false), m_version(vr) {}
+
+ bool isCodeInjection() const
+ {
+ return modifiers & CodeInjection;
+ }
+ void setIsThread(bool flag)
+ {
+ m_thread = flag;
+ }
+ bool isThread() const
+ {
+ return m_thread;
+ }
+ bool allowThread() const
+ {
+ return m_allowThread;
+ }
+ void setAllowThread(bool allow)
+ {
+ m_allowThread = allow;
+ }
+ double version() const
+ {
+ return m_version;
+ }
+
+ bool operator!=(const FunctionModification& other) const;
+ bool operator==(const FunctionModification& other) const;
+
+
+ QString toString() const;
+
+ QString signature;
+ QString association;
+ CodeSnipList snips;
+
+ QVector<ArgumentModification> argument_mods;
+
+private:
+ bool m_thread;
+ bool m_allowThread;
+ double m_version;
+
+
+};
+
+struct FieldModification: public Modification
+{
+ bool isReadable() const
+ {
+ return modifiers & Readable;
+ }
+ bool isWritable() const
+ {
+ return modifiers & Writable;
+ }
+
+ QString name;
+};
+
+/**
+* \internal
+* Struct used to store information about functions added by the typesystem.
+* This info will be used later to create a fake AbstractMetaFunction which
+* will be inserted into the right AbstractMetaClass.
+*/
+struct AddedFunction
+{
+ /// Function access types.
+ enum Access {
+ Protected = 0x1,
+ Public = 0x2
+ };
+
+ /**
+ * \internal
+ * Internal struct used to store information about arguments and return type of the
+ * functions added by the type system. This information is later used to create
+ * AbstractMetaType and AbstractMetaArgument for the AbstractMetaFunctions.
+ */
+ struct TypeInfo {
+ TypeInfo() : isConstant(false), indirections(0), isReference(false) {}
+ static TypeInfo fromSignature(const QString& signature);
+
+ QString name;
+ bool isConstant;
+ int indirections;
+ bool isReference;
+ QString defaultValue;
+ };
+
+ /// Creates a new AddedFunction with a signature and a return type.
+ AddedFunction(QString signature, QString returnType, double vr);
+ AddedFunction() : m_access(Protected), m_isConst(false), m_isStatic(false), m_version(0) {}
+
+ /// Returns the function name.
+ QString name() const
+ {
+ return m_name;
+ }
+
+ /// Set the function access type.
+ void setAccess(Access access)
+ {
+ m_access = access;
+ }
+
+ /// Returns the function access type.
+ Access access() const
+ {
+ return m_access;
+ }
+
+ /// Returns the function return type.
+ TypeInfo returnType() const
+ {
+ return m_returnType;
+ }
+
+ /// Returns a list of argument type infos.
+ QVector<TypeInfo> arguments() const
+ {
+ return m_arguments;
+ }
+
+ /// Returns true if this is a constant method.
+ bool isConstant() const
+ {
+ return m_isConst;
+ }
+
+ /// Set this method static.
+ void setStatic(bool value)
+ {
+ m_isStatic = value;
+ }
+
+ /// Returns true if this is a static method.
+ bool isStatic() const
+ {
+ return m_isStatic;
+ }
+
+ double version() const
+ {
+ return m_version;
+ }
+private:
+ QString m_name;
+ Access m_access;
+ QVector<TypeInfo> m_arguments;
+ TypeInfo m_returnType;
+ bool m_isConst;
+ bool m_isStatic;
+ double m_version;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti);
+QDebug operator<<(QDebug d, const AddedFunction &af);
+#endif
+
+struct ExpensePolicy
+{
+ ExpensePolicy() : limit(-1) {}
+ int limit;
+ QString cost;
+ bool isValid() const
+ {
+ return limit >= 0;
+ }
+};
+
+class InterfaceTypeEntry;
+class ObjectTypeEntry;
+
+class DocModification
+{
+public:
+ DocModification() : format(TypeSystem::NativeCode), m_mode(TypeSystem::DocModificationXPathReplace), m_version(0) {}
+ DocModification(const QString& xpath, const QString& signature, double vr)
+ : format(TypeSystem::NativeCode), m_mode(TypeSystem::DocModificationXPathReplace),
+ m_xpath(xpath), m_signature(signature), m_version(vr) {}
+ DocModification(TypeSystem::DocModificationMode mode, const QString& signature, double vr)
+ : m_mode(mode), m_signature(signature), m_version(vr) {}
+
+ void setCode(const QString& code) { m_code = code; }
+ void setCode(const QStringRef& code) { m_code = code.toString(); }
+
+ QString code() const
+ {
+ return m_code;
+ }
+ QString xpath() const
+ {
+ return m_xpath;
+ }
+ QString signature() const
+ {
+ return m_signature;
+ }
+ TypeSystem::DocModificationMode mode() const
+ {
+ return m_mode;
+ }
+ double version() const
+ {
+ return m_version;
+ }
+
+ TypeSystem::Language format;
+
+private:
+ TypeSystem::DocModificationMode m_mode;
+ QString m_code;
+ QString m_xpath;
+ QString m_signature;
+ double m_version;
+};
+
+class CustomConversion;
+
+class TypeEntry
+{
+ Q_GADGET
+public:
+ enum Type {
+ PrimitiveType,
+ VoidType,
+ VarargsType,
+ FlagsType,
+ EnumType,
+ EnumValue,
+ TemplateArgumentType,
+ ThreadType,
+ BasicValueType,
+ StringType,
+ ContainerType,
+ InterfaceType,
+ ObjectType,
+ NamespaceType,
+ VariantType,
+ JObjectWrapperType,
+ CharType,
+ ArrayType,
+ TypeSystemType,
+ CustomType,
+ TargetLangType,
+ FunctionType,
+ SmartPointerType
+ };
+ Q_ENUM(Type)
+
+ enum CodeGeneration {
+ GenerateTargetLang = 0x0001,
+ GenerateCpp = 0x0002,
+ GenerateForSubclass = 0x0004,
+
+ GenerateNothing = 0,
+ GenerateAll = 0xffff,
+ GenerateCode = GenerateTargetLang | GenerateCpp
+ };
+ Q_ENUM(CodeGeneration)
+
+ TypeEntry(const QString &name, Type t, double vr)
+ : m_name(name),
+ m_type(t),
+ m_codeGeneration(GenerateAll),
+ m_preferredConversion(true),
+ m_stream(false),
+ m_version(vr)
+ {
+ };
+
+ virtual ~TypeEntry();
+
+ Type type() const
+ {
+ return m_type;
+ }
+ bool isPrimitive() const
+ {
+ return m_type == PrimitiveType;
+ }
+ bool isEnum() const
+ {
+ return m_type == EnumType;
+ }
+ bool isFlags() const
+ {
+ return m_type == FlagsType;
+ }
+ bool isInterface() const
+ {
+ return m_type == InterfaceType;
+ }
+ bool isObject() const
+ {
+ return m_type == ObjectType;
+ }
+ bool isString() const
+ {
+ return m_type == StringType;
+ }
+ bool isChar() const
+ {
+ return m_type == CharType;
+ }
+ bool isNamespace() const
+ {
+ return m_type == NamespaceType;
+ }
+ bool isContainer() const
+ {
+ return m_type == ContainerType;
+ }
+ bool isSmartPointer() const
+ {
+ return m_type == SmartPointerType;
+ }
+ bool isVariant() const
+ {
+ return m_type == VariantType;
+ }
+ bool isJObjectWrapper() const
+ {
+ return m_type == JObjectWrapperType;
+ }
+ bool isArray() const
+ {
+ return m_type == ArrayType;
+ }
+ bool isTemplateArgument() const
+ {
+ return m_type == TemplateArgumentType;
+ }
+ bool isVoid() const
+ {
+ return m_type == VoidType;
+ }
+ bool isVarargs() const
+ {
+ return m_type == VarargsType;
+ }
+ bool isThread() const
+ {
+ return m_type == ThreadType;
+ }
+ bool isCustom() const
+ {
+ return m_type == CustomType;
+ }
+ bool isBasicValue() const
+ {
+ return m_type == BasicValueType;
+ }
+ bool isTypeSystem() const
+ {
+ return m_type == TypeSystemType;
+ }
+ bool isFunction() const
+ {
+ return m_type == FunctionType;
+ }
+ bool isEnumValue() const
+ {
+ return m_type == EnumValue;
+ }
+
+ virtual bool preferredConversion() const
+ {
+ return m_preferredConversion;
+ }
+ virtual void setPreferredConversion(bool b)
+ {
+ m_preferredConversion = b;
+ }
+
+ bool stream() const
+ {
+ return m_stream;
+ }
+
+ void setStream(bool b)
+ {
+ m_stream = b;
+ }
+
+ // The type's name in C++, fully qualified
+ QString name() const
+ {
+ return m_name;
+ }
+
+ uint codeGeneration() const
+ {
+ return m_codeGeneration;
+ }
+ void setCodeGeneration(uint cg)
+ {
+ m_codeGeneration = cg;
+ }
+
+ // Returns true if code must be generated for this entry,
+ // it will return false in case of types coming from typesystems
+ // included for reference only.
+ // NOTE: 'GenerateForSubclass' means 'generate="no"'
+ // on 'load-typesystem' tag
+ inline bool generateCode() const
+ {
+ return m_codeGeneration != TypeEntry::GenerateForSubclass
+ && m_codeGeneration != TypeEntry::GenerateNothing;
+ }
+
+ virtual QString qualifiedCppName() const
+ {
+ return m_name;
+ }
+
+ /**
+ * Its type's name in target language API
+ * The target language API name represents how this type is
+ * referred on low level code for the target language.
+ * Examples: for Java this would be a JNI name, for Python
+ * it should represent the CPython type name.
+ * /return string representing the target language API name
+ * for this type entry
+ */
+ virtual QString targetLangApiName() const
+ {
+ return m_name;
+ }
+
+ // The type's name in TargetLang
+ virtual QString targetLangName() const
+ {
+ return m_name;
+ }
+
+ // The type to lookup when converting to TargetLang
+ virtual QString lookupName() const
+ {
+ return targetLangName();
+ }
+
+ // The package
+ virtual QString targetLangPackage() const
+ {
+ return QString();
+ }
+
+ virtual QString qualifiedTargetLangName() const
+ {
+ QString pkg = targetLangPackage();
+ if (pkg.isEmpty())
+ return targetLangName();
+ return pkg + QLatin1Char('.') + targetLangName();
+ }
+
+ virtual InterfaceTypeEntry *designatedInterface() const
+ {
+ return 0;
+ }
+
+ void setCustomConstructor(const CustomFunction &func)
+ {
+ m_customConstructor = func;
+ }
+ CustomFunction customConstructor() const
+ {
+ return m_customConstructor;
+ }
+
+ void setCustomDestructor(const CustomFunction &func)
+ {
+ m_customDestructor = func;
+ }
+ CustomFunction customDestructor() const
+ {
+ return m_customDestructor;
+ }
+
+ virtual bool isValue() const
+ {
+ return false;
+ }
+ virtual bool isComplex() const
+ {
+ return false;
+ }
+
+ virtual bool isNativeIdBased() const
+ {
+ return false;
+ }
+
+ CodeSnipList codeSnips() const;
+ void setCodeSnips(const CodeSnipList &codeSnips)
+ {
+ m_codeSnips = codeSnips;
+ }
+ void addCodeSnip(const CodeSnip &codeSnip)
+ {
+ m_codeSnips << codeSnip;
+ }
+
+ void setDocModification(const DocModificationList& docMods)
+ {
+ m_docModifications << docMods;
+ }
+ DocModificationList docModifications() const
+ {
+ return m_docModifications;
+ }
+
+ IncludeList extraIncludes() const
+ {
+ return m_extraIncludes;
+ }
+ void setExtraIncludes(const IncludeList &includes)
+ {
+ m_extraIncludes = includes;
+ }
+ void addExtraInclude(const Include &include)
+ {
+ if (!m_includesUsed.value(include.name(), false)) {
+ m_extraIncludes << include;
+ m_includesUsed[include.name()] = true;
+ }
+ }
+
+ Include include() const
+ {
+ return m_include;
+ }
+ void setInclude(const Include &inc)
+ {
+ // This is a workaround for preventing double inclusion of the QSharedPointer implementation
+ // header, which does not use header guards. In the previous parser this was not a problem
+ // because the Q_QDOC define was set, and the implementation header was never included.
+ if (inc.name() == QLatin1String("qsharedpointer_impl.h"))
+ m_include = Include(inc.type(), QLatin1String("qsharedpointer.h"));
+ else
+ m_include = inc;
+ }
+
+ // Replace conversionRule arg to CodeSnip in future version
+ /// Set the type convertion rule
+ void setConversionRule(const QString& conversionRule)
+ {
+ m_conversionRule = conversionRule;
+ }
+
+ /// Returns the type convertion rule
+ QString conversionRule() const
+ {
+ //skip conversions flag
+ return m_conversionRule.mid(1);
+ }
+
+ /// Returns true if there are any conversiton rule for this type, false otherwise.
+ bool hasConversionRule() const
+ {
+ return !m_conversionRule.isEmpty();
+ }
+
+ double version() const
+ {
+ return m_version;
+ }
+
+ /// TODO-CONVERTER: mark as deprecated
+ bool hasNativeConversionRule() const
+ {
+ return m_conversionRule.startsWith(QLatin1String(NATIVE_CONVERSION_RULE_FLAG));
+ }
+
+ /// TODO-CONVERTER: mark as deprecated
+ bool hasTargetConversionRule() const
+ {
+ return m_conversionRule.startsWith(QLatin1String(TARGET_CONVERSION_RULE_FLAG));
+ }
+
+ bool isCppPrimitive() const;
+
+ bool hasCustomConversion() const;
+ void setCustomConversion(CustomConversion* customConversion);
+ CustomConversion* customConversion() const;
+private:
+ QString m_name;
+ Type m_type;
+ uint m_codeGeneration;
+ CustomFunction m_customConstructor;
+ CustomFunction m_customDestructor;
+ bool m_preferredConversion;
+ CodeSnipList m_codeSnips;
+ DocModificationList m_docModifications;
+ IncludeList m_extraIncludes;
+ Include m_include;
+ QHash<QString, bool> m_includesUsed;
+ QString m_conversionRule;
+ bool m_stream;
+ double m_version;
+};
+
+class TypeSystemTypeEntry : public TypeEntry
+{
+public:
+ TypeSystemTypeEntry(const QString &name, double vr)
+ : TypeEntry(name, TypeSystemType, vr)
+ {
+ };
+};
+
+class VoidTypeEntry : public TypeEntry
+{
+public:
+ VoidTypeEntry() : TypeEntry(QLatin1String("void"), VoidType, 0) { }
+};
+
+class VarargsTypeEntry : public TypeEntry
+{
+public:
+ VarargsTypeEntry() : TypeEntry(QLatin1String("..."), VarargsType, 0) { }
+};
+
+class TemplateArgumentEntry : public TypeEntry
+{
+public:
+ TemplateArgumentEntry(const QString &name, double vr)
+ : TypeEntry(name, TemplateArgumentType, vr), m_ordinal(0)
+ {
+ }
+
+ int ordinal() const
+ {
+ return m_ordinal;
+ }
+ void setOrdinal(int o)
+ {
+ m_ordinal = o;
+ }
+
+private:
+ int m_ordinal;
+};
+
+class ArrayTypeEntry : public TypeEntry
+{
+public:
+ ArrayTypeEntry(const TypeEntry *nested_type, double vr)
+ : TypeEntry(QLatin1String("Array"), ArrayType, vr), m_nestedType(nested_type)
+ {
+ Q_ASSERT(m_nestedType);
+ }
+
+ void setNestedTypeEntry(TypeEntry *nested)
+ {
+ m_nestedType = nested;
+ }
+ const TypeEntry *nestedTypeEntry() const
+ {
+ return m_nestedType;
+ }
+
+ QString targetLangName() const override
+ {
+ return m_nestedType->targetLangName() + QLatin1String("[]");
+ }
+ QString targetLangApiName() const override
+ {
+ if (m_nestedType->isPrimitive())
+ return m_nestedType->targetLangApiName() + QLatin1String("Array");
+ else
+ return QLatin1String("jobjectArray");
+ }
+
+private:
+ const TypeEntry *m_nestedType;
+};
+
+
+class PrimitiveTypeEntry : public TypeEntry
+{
+public:
+ PrimitiveTypeEntry(const QString &name, double vr)
+ : TypeEntry(name, PrimitiveType, vr),
+ m_preferredConversion(true),
+ m_preferredTargetLangType(true),
+ m_referencedTypeEntry(0)
+ {
+ }
+
+ QString targetLangName() const override
+ {
+ return m_targetLangName;
+ }
+ void setTargetLangName(const QString &targetLangName)
+ {
+ m_targetLangName = targetLangName;
+ }
+
+ QString targetLangApiName() const override
+ {
+ return m_targetLangApiName;
+ }
+ void setTargetLangApiName(const QString &targetLangApiName)
+ {
+ m_targetLangApiName = targetLangApiName;
+ }
+
+ QString defaultConstructor() const
+ {
+ return m_defaultConstructor;
+ }
+ void setDefaultConstructor(const QString& defaultConstructor)
+ {
+ m_defaultConstructor = defaultConstructor;
+ }
+ bool hasDefaultConstructor() const
+ {
+ return !m_defaultConstructor.isEmpty();
+ }
+
+ /**
+ * The PrimitiveTypeEntry pointed by this type entry if it
+ * represents a typedef).
+ * /return the type referenced by the typedef, or a null pointer
+ * if the current object is not an typedef
+ */
+ PrimitiveTypeEntry* referencedTypeEntry() const { return m_referencedTypeEntry; }
+
+ /**
+ * Defines type referenced by this entry.
+ * /param referencedTypeEntry type referenced by this entry
+ */
+ void setReferencedTypeEntry(PrimitiveTypeEntry* referencedTypeEntry)
+ {
+ m_referencedTypeEntry = referencedTypeEntry;
+ }
+
+ /**
+ * Finds the most basic primitive type that the typedef represents,
+ * i.e. a type that is not an typedef'ed.
+ * /return the most basic non-typedef'ed primitive type represented
+ * by this typedef
+ */
+ PrimitiveTypeEntry* basicReferencedTypeEntry() const;
+
+ bool preferredConversion() const override
+ {
+ return m_preferredConversion;
+ }
+ void setPreferredConversion(bool b) override
+ {
+ m_preferredConversion = b;
+ }
+
+ bool preferredTargetLangType() const
+ {
+ return m_preferredTargetLangType;
+ }
+ void setPreferredTargetLangType(bool b)
+ {
+ m_preferredTargetLangType = b;
+ }
+
+ void setTargetLangPackage(const QString& package);
+ QString targetLangPackage() const override;
+private:
+ QString m_targetLangName;
+ QString m_targetLangApiName;
+ QString m_defaultConstructor;
+ uint m_preferredConversion : 1;
+ uint m_preferredTargetLangType : 1;
+ PrimitiveTypeEntry* m_referencedTypeEntry;
+};
+
+struct EnumValueRedirection
+{
+ EnumValueRedirection() {}
+ EnumValueRedirection(const QString &rej, const QString &us)
+ : rejected(rej),
+ used(us)
+ {
+ }
+ QString rejected;
+ QString used;
+};
+
+class EnumTypeEntry : public TypeEntry
+{
+public:
+ EnumTypeEntry(const QString &nspace, const QString &enumName, double vr)
+ : TypeEntry(nspace.isEmpty() ? enumName : nspace + QLatin1String("::") + enumName,
+ EnumType, vr),
+ m_qualifier(nspace),
+ m_targetLangName(enumName),
+ m_flags(0),
+ m_extensible(false),
+ m_forceInteger(false),
+ m_anonymous(false)
+ {
+ }
+
+ QString targetLangPackage() const
+ {
+ return m_packageName;
+ }
+ void setTargetLangPackage(const QString &package)
+ {
+ m_packageName = package;
+ }
+
+ QString targetLangName() const
+ {
+ return m_targetLangName;
+ }
+ QString targetLangQualifier() const;
+ QString qualifiedTargetLangName() const override
+ {
+ QString qualifiedName;
+ QString pkg = targetLangPackage();
+ QString qualifier = targetLangQualifier();
+
+ if (!pkg.isEmpty())
+ qualifiedName += pkg + QLatin1Char('.');
+ if (!qualifier.isEmpty())
+ qualifiedName += qualifier + QLatin1Char('.');
+ qualifiedName += targetLangName();
+
+ return qualifiedName;
+ }
+
+ QString targetLangApiName() const override;
+
+ QString qualifier() const
+ {
+ return m_qualifier;
+ }
+ void setQualifier(const QString &q)
+ {
+ m_qualifier = q;
+ }
+
+ bool preferredConversion() const override
+ {
+ return false;
+ }
+
+ bool isBoundsChecked() const
+ {
+ return m_lowerBound.isEmpty() && m_upperBound.isEmpty();
+ }
+
+ QString upperBound() const
+ {
+ return m_upperBound;
+ }
+ void setUpperBound(const QString &bound)
+ {
+ m_upperBound = bound;
+ }
+
+ QString lowerBound() const
+ {
+ return m_lowerBound;
+ }
+ void setLowerBound(const QString &bound)
+ {
+ m_lowerBound = bound;
+ }
+
+ void setFlags(FlagsTypeEntry *flags)
+ {
+ m_flags = flags;
+ }
+ FlagsTypeEntry *flags() const
+ {
+ return m_flags;
+ }
+
+ bool isExtensible() const
+ {
+ return m_extensible;
+ }
+ void setExtensible(bool is)
+ {
+ m_extensible = is;
+ }
+
+ bool isEnumValueRejected(const QString &name)
+ {
+ return m_rejectedEnums.contains(name);
+ }
+ void addEnumValueRejection(const QString &name)
+ {
+ m_rejectedEnums << name;
+ }
+ QStringList enumValueRejections() const
+ {
+ return m_rejectedEnums;
+ }
+
+ void addEnumValueRedirection(const QString &rejected, const QString &usedValue);
+ QString enumValueRedirection(const QString &value) const;
+
+ bool forceInteger() const
+ {
+ return m_forceInteger;
+ }
+ void setForceInteger(bool force)
+ {
+ m_forceInteger = force;
+ }
+
+ bool isAnonymous() const
+ {
+ return m_anonymous;
+ }
+ void setAnonymous(bool anonymous)
+ {
+ m_anonymous = anonymous;
+ }
+
+private:
+ QString m_packageName;
+ QString m_qualifier;
+ QString m_targetLangName;
+
+ QString m_lowerBound;
+ QString m_upperBound;
+
+ QStringList m_rejectedEnums;
+ QVector<EnumValueRedirection> m_enumRedirections;
+
+ FlagsTypeEntry *m_flags;
+
+ bool m_extensible;
+ bool m_forceInteger;
+ bool m_anonymous;
+};
+
+class EnumValueTypeEntry : public TypeEntry
+{
+public:
+ EnumValueTypeEntry(const QString& name, const QString& value, const EnumTypeEntry* enclosingEnum, double vr)
+ : TypeEntry(name, TypeEntry::EnumValue, vr), m_value(value), m_enclosingEnum(enclosingEnum)
+ {
+ }
+
+ QString value() const { return m_value; }
+ const EnumTypeEntry* enclosingEnum() const { return m_enclosingEnum; }
+private:
+ QString m_value;
+ const EnumTypeEntry* m_enclosingEnum;
+};
+
+class FlagsTypeEntry : public TypeEntry
+{
+public:
+ FlagsTypeEntry(const QString &name, double vr) : TypeEntry(name, FlagsType, vr), m_enum(0)
+ {
+ }
+
+ QString qualifiedTargetLangName() const override;
+ QString targetLangName() const override
+ {
+ return m_targetLangName;
+ }
+ QString targetLangApiName() const override;
+ bool preferredConversion() const override
+ {
+ return false;
+ }
+
+ QString originalName() const
+ {
+ return m_originalName;
+ }
+ void setOriginalName(const QString &s)
+ {
+ m_originalName = s;
+ }
+
+ QString flagsName() const
+ {
+ return m_targetLangName;
+ }
+ void setFlagsName(const QString &name)
+ {
+ m_targetLangName = name;
+ }
+
+ bool forceInteger() const
+ {
+ return m_enum->forceInteger();
+ }
+
+ EnumTypeEntry *originator() const
+ {
+ return m_enum;
+ }
+ void setOriginator(EnumTypeEntry *e)
+ {
+ m_enum = e;
+ }
+
+ QString targetLangPackage() const override
+ {
+ return m_enum->targetLangPackage();
+ }
+
+private:
+ QString m_originalName;
+ QString m_targetLangName;
+ EnumTypeEntry *m_enum;
+};
+
+
+class ComplexTypeEntry : public TypeEntry
+{
+public:
+ enum TypeFlag {
+ ForceAbstract = 0x1,
+ DeleteInMainThread = 0x2,
+ Deprecated = 0x4
+ };
+ typedef QFlags<TypeFlag> TypeFlags;
+
+ enum CopyableFlag {
+ CopyableSet,
+ NonCopyableSet,
+ Unknown
+ };
+
+ ComplexTypeEntry(const QString &name, Type t, double vr)
+ : TypeEntry(QString(name).replace(QLatin1String(".*::"), QString()), t, vr),
+ m_qualifiedCppName(name),
+ m_qobject(false),
+ m_polymorphicBase(false),
+ m_genericClass(false),
+ m_typeFlags(0),
+ m_copyableFlag(Unknown),
+ m_baseContainerType(0)
+ {
+ }
+
+ bool isComplex() const
+ {
+ return true;
+ }
+
+ ComplexTypeEntry *copy() const
+ {
+ ComplexTypeEntry *centry = new ComplexTypeEntry(name(), type(), version());
+ centry->setInclude(include());
+ centry->setExtraIncludes(extraIncludes());
+ centry->setAddedFunctions(addedFunctions());
+ centry->setFunctionModifications(functionModifications());
+ centry->setFieldModifications(fieldModifications());
+ centry->setQObject(isQObject());
+ centry->setDefaultSuperclass(defaultSuperclass());
+ centry->setCodeSnips(codeSnips());
+ centry->setTargetLangPackage(targetLangPackage());
+ centry->setBaseContainerType(baseContainerType());
+ centry->setDefaultConstructor(defaultConstructor());
+
+ return centry;
+ }
+
+ void setLookupName(const QString &name)
+ {
+ m_lookupName = name;
+ }
+
+ QString lookupName() const override
+ {
+ return m_lookupName.isEmpty() ? targetLangName() : m_lookupName;
+ }
+
+ QString targetLangApiName() const override;
+
+ void setTypeFlags(TypeFlags flags)
+ {
+ m_typeFlags = flags;
+ }
+
+ TypeFlags typeFlags() const
+ {
+ return m_typeFlags;
+ }
+
+ FunctionModificationList functionModifications() const
+ {
+ return m_functionMods;
+ }
+ void setFunctionModifications(const FunctionModificationList &functionModifications)
+ {
+ m_functionMods = functionModifications;
+ }
+ void addFunctionModification(const FunctionModification &functionModification)
+ {
+ m_functionMods << functionModification;
+ }
+ FunctionModificationList functionModifications(const QString &signature) const;
+
+ AddedFunctionList addedFunctions() const
+ {
+ return m_addedFunctions;
+ }
+ void setAddedFunctions(const AddedFunctionList &addedFunctions)
+ {
+ m_addedFunctions = addedFunctions;
+ }
+ void addNewFunction(const AddedFunction &addedFunction)
+ {
+ m_addedFunctions << addedFunction;
+ }
+
+ FieldModification fieldModification(const QString &name) const;
+ void setFieldModifications(const FieldModificationList &mods)
+ {
+ m_fieldMods = mods;
+ }
+ FieldModificationList fieldModifications() const
+ {
+ return m_fieldMods;
+ }
+
+ QString targetLangPackage() const
+ {
+ return m_package;
+ }
+ void setTargetLangPackage(const QString &package)
+ {
+ m_package = package;
+ }
+
+ bool isQObject() const
+ {
+ return m_qobject;
+ }
+ void setQObject(bool qobject)
+ {
+ m_qobject = qobject;
+ }
+
+ QString defaultSuperclass() const
+ {
+ return m_defaultSuperclass;
+ }
+ void setDefaultSuperclass(const QString &sc)
+ {
+ m_defaultSuperclass = sc;
+ }
+
+ QString qualifiedCppName() const override
+ {
+ return m_qualifiedCppName;
+ }
+
+
+ void setIsPolymorphicBase(bool on)
+ {
+ m_polymorphicBase = on;
+ }
+ bool isPolymorphicBase() const
+ {
+ return m_polymorphicBase;
+ }
+
+ void setPolymorphicIdValue(const QString &value)
+ {
+ m_polymorphicIdValue = value;
+ }
+ QString polymorphicIdValue() const
+ {
+ return m_polymorphicIdValue;
+ }
+
+ void setHeldType(const QString &value)
+ {
+ m_heldTypeValue = value;
+ }
+ QString heldTypeValue() const
+ {
+ return m_heldTypeValue;
+ }
+
+
+ void setExpensePolicy(const ExpensePolicy &policy)
+ {
+ m_expensePolicy = policy;
+ }
+ const ExpensePolicy &expensePolicy() const
+ {
+ return m_expensePolicy;
+ }
+
+ QString targetType() const
+ {
+ return m_targetType;
+ }
+ void setTargetType(const QString &code)
+ {
+ m_targetType = code;
+ }
+
+ QString targetLangName() const override
+ {
+ return m_targetLangName.isEmpty()
+ ? TypeEntry::targetLangName()
+ : m_targetLangName;
+ }
+ void setTargetLangName(const QString &name)
+ {
+ m_targetLangName = name;
+ }
+
+ bool isGenericClass() const
+ {
+ return m_genericClass;
+ }
+ void setGenericClass(bool isGeneric)
+ {
+ m_genericClass = isGeneric;
+ }
+
+ CopyableFlag copyable() const
+ {
+ return m_copyableFlag;
+ }
+ void setCopyable(CopyableFlag flag)
+ {
+ m_copyableFlag = flag;
+ }
+
+ QString hashFunction() const
+ {
+ return m_hashFunction;
+ }
+ void setHashFunction(QString hashFunction)
+ {
+ m_hashFunction = hashFunction;
+ }
+
+ void setBaseContainerType(const ComplexTypeEntry *baseContainer)
+ {
+ m_baseContainerType = baseContainer;
+ }
+
+ const ComplexTypeEntry* baseContainerType() const
+ {
+ return m_baseContainerType;
+ }
+
+ QString defaultConstructor() const;
+ void setDefaultConstructor(const QString& defaultConstructor);
+ bool hasDefaultConstructor() const;
+
+private:
+ AddedFunctionList m_addedFunctions;
+ FunctionModificationList m_functionMods;
+ FieldModificationList m_fieldMods;
+ QString m_package;
+ QString m_defaultSuperclass;
+ QString m_qualifiedCppName;
+ QString m_targetLangName;
+
+ uint m_qobject : 1;
+ uint m_polymorphicBase : 1;
+ uint m_genericClass : 1;
+
+ QString m_polymorphicIdValue;
+ QString m_heldTypeValue;
+ QString m_lookupName;
+ QString m_targetType;
+ ExpensePolicy m_expensePolicy;
+ TypeFlags m_typeFlags;
+ CopyableFlag m_copyableFlag;
+ QString m_hashFunction;
+
+ const ComplexTypeEntry* m_baseContainerType;
+};
+
+class ContainerTypeEntry : public ComplexTypeEntry
+{
+ Q_GADGET
+public:
+ enum Type {
+ NoContainer,
+ ListContainer,
+ StringListContainer,
+ LinkedListContainer,
+ VectorContainer,
+ StackContainer,
+ QueueContainer,
+ SetContainer,
+ MapContainer,
+ MultiMapContainer,
+ HashContainer,
+ MultiHashContainer,
+ PairContainer,
+ };
+ Q_ENUM(Type)
+
+ ContainerTypeEntry(const QString &name, Type type, double vr)
+ : ComplexTypeEntry(name, ContainerType, vr), m_type(type)
+ {
+ setCodeGeneration(GenerateForSubclass);
+ }
+
+ Type type() const
+ {
+ return m_type;
+ }
+
+ QString typeName() const;
+ QString targetLangName() const;
+ QString targetLangPackage() const;
+ QString qualifiedCppName() const;
+
+ static Type containerTypeFromString(QString typeName)
+ {
+ static QHash<QString, Type> m_stringToContainerType;
+ if (m_stringToContainerType.isEmpty()) {
+ m_stringToContainerType.insert(QLatin1String("list"), ListContainer);
+ m_stringToContainerType.insert(QLatin1String("string-list"), StringListContainer);
+ m_stringToContainerType.insert(QLatin1String("linked-list"), LinkedListContainer);
+ m_stringToContainerType.insert(QLatin1String("vector"), VectorContainer);
+ m_stringToContainerType.insert(QLatin1String("stack"), StackContainer);
+ m_stringToContainerType.insert(QLatin1String("queue"), QueueContainer);
+ m_stringToContainerType.insert(QLatin1String("set"), SetContainer);
+ m_stringToContainerType.insert(QLatin1String("map"), MapContainer);
+ m_stringToContainerType.insert(QLatin1String("multi-map"), MultiMapContainer);
+ m_stringToContainerType.insert(QLatin1String("hash"), HashContainer);
+ m_stringToContainerType.insert(QLatin1String("multi-hash"), MultiHashContainer);
+ m_stringToContainerType.insert(QLatin1String("pair"), PairContainer);
+ }
+ return m_stringToContainerType.value(typeName, NoContainer);
+ }
+
+private:
+ Type m_type;
+};
+
+class SmartPointerTypeEntry : public ComplexTypeEntry
+{
+public:
+ SmartPointerTypeEntry(const QString &name,
+ const QString &getterName,
+ const QString &smartPointerType,
+ const QString &refCountMethodName,
+ double vr)
+ : ComplexTypeEntry(name, SmartPointerType, vr),
+ m_getterName(getterName),
+ m_smartPointerType(smartPointerType),
+ m_refCountMethodName(refCountMethodName)
+ {
+ }
+
+ QString getter() const
+ {
+ return m_getterName;
+ }
+
+ QString refCountMethodName() const
+ {
+ return m_refCountMethodName;
+ }
+
+private:
+ QString m_getterName;
+ QString m_smartPointerType;
+ QString m_refCountMethodName;
+};
+
+class NamespaceTypeEntry : public ComplexTypeEntry
+{
+public:
+ NamespaceTypeEntry(const QString &name, double vr) : ComplexTypeEntry(name, NamespaceType, vr) { }
+};
+
+
+class ValueTypeEntry : public ComplexTypeEntry
+{
+public:
+ ValueTypeEntry(const QString &name, double vr) : ComplexTypeEntry(name, BasicValueType, vr) { }
+
+ bool isValue() const override
+ {
+ return true;
+ }
+
+ bool isNativeIdBased() const override
+ {
+ return true;
+ }
+
+protected:
+ ValueTypeEntry(const QString &name, Type t, double vr) : ComplexTypeEntry(name, t, vr) { }
+};
+
+
+class StringTypeEntry : public ValueTypeEntry
+{
+public:
+ StringTypeEntry(const QString &name, double vr)
+ : ValueTypeEntry(name, StringType, vr)
+ {
+ setCodeGeneration(GenerateNothing);
+ }
+
+ QString targetLangApiName() const override;
+ QString targetLangName() const override;
+ QString targetLangPackage() const override;
+
+ bool isNativeIdBased() const override
+ {
+ return false;
+ }
+};
+
+class CharTypeEntry : public ValueTypeEntry
+{
+public:
+ CharTypeEntry(const QString &name, double vr) : ValueTypeEntry(name, CharType, vr)
+ {
+ setCodeGeneration(GenerateNothing);
+ }
+
+ QString targetLangApiName() const override;
+ QString targetLangName() const override;
+ QString targetLangPackage() const override
+ {
+ return QString();
+ }
+
+ bool isNativeIdBased() const override
+ {
+ return false;
+ }
+};
+
+class VariantTypeEntry: public ValueTypeEntry
+{
+public:
+ VariantTypeEntry(const QString &name, double vr) : ValueTypeEntry(name, VariantType, vr) { }
+
+ QString targetLangApiName() const override;
+ QString targetLangName() const override;
+ QString targetLangPackage() const override;
+
+ bool isNativeIdBased() const override
+ {
+ return false;
+ }
+};
+
+
+class InterfaceTypeEntry : public ComplexTypeEntry
+{
+public:
+ InterfaceTypeEntry(const QString &name, double vr)
+ : ComplexTypeEntry(name, InterfaceType, vr) {}
+
+ static QString interfaceName(const QString &name)
+ {
+ return name + QLatin1String("Interface");
+ }
+
+ ObjectTypeEntry *origin() const
+ {
+ return m_origin;
+ }
+ void setOrigin(ObjectTypeEntry *origin)
+ {
+ m_origin = origin;
+ }
+
+ bool isNativeIdBased() const override
+ {
+ return true;
+ }
+ QString qualifiedCppName() const override
+ {
+ const int len = ComplexTypeEntry::qualifiedCppName().length() - interfaceName(QString()).length();
+ return ComplexTypeEntry::qualifiedCppName().left(len);
+ }
+
+private:
+ ObjectTypeEntry *m_origin;
+};
+
+
+class FunctionTypeEntry : public TypeEntry
+{
+public:
+ FunctionTypeEntry(const QString& name, const QString& signature, double vr)
+ : TypeEntry(name, FunctionType, vr)
+ {
+ addSignature(signature);
+ }
+ void addSignature(const QString& signature)
+ {
+ m_signatures << signature;
+ }
+
+ QStringList signatures() const
+ {
+ return m_signatures;
+ }
+
+ bool hasSignature(const QString& signature) const
+ {
+ return m_signatures.contains(signature);
+ }
+private:
+ QStringList m_signatures;
+};
+
+class ObjectTypeEntry : public ComplexTypeEntry
+{
+public:
+ ObjectTypeEntry(const QString &name, double vr)
+ : ComplexTypeEntry(name, ObjectType, vr), m_interface(0) {}
+
+ InterfaceTypeEntry *designatedInterface() const
+ {
+ return m_interface;
+ }
+ void setDesignatedInterface(InterfaceTypeEntry *entry)
+ {
+ m_interface = entry;
+ }
+
+ bool isNativeIdBased() const override
+ {
+ return true;
+ }
+
+private:
+ InterfaceTypeEntry *m_interface;
+};
+
+struct TypeRejection
+{
+ enum MatchType
+ {
+ ExcludeClass, // Match className only
+ Function, // Match className and function name
+ Field, // Match className and field name
+ Enum, // Match className and enum name
+ ArgumentType, // Match className and argument type
+ ReturnType // Match className and return type
+ };
+
+ QRegularExpression className;
+ QRegularExpression pattern;
+ MatchType matchType;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const TypeRejection &r);
+#endif
+
+QString fixCppTypeName(const QString &name);
+
+class CustomConversion
+{
+public:
+ CustomConversion(TypeEntry* ownerType);
+ ~CustomConversion();
+
+ const TypeEntry* ownerType() const;
+ QString nativeToTargetConversion() const;
+ void setNativeToTargetConversion(const QString& nativeToTargetConversion);
+
+ class TargetToNativeConversion
+ {
+ public:
+ TargetToNativeConversion(const QString& sourceTypeName,
+ const QString& sourceTypeCheck,
+ const QString& conversion = QString());
+ ~TargetToNativeConversion();
+
+ const TypeEntry* sourceType() const;
+ void setSourceType(const TypeEntry* sourceType);
+ bool isCustomType() const;
+ QString sourceTypeName() const;
+ QString sourceTypeCheck() const;
+ QString conversion() const;
+ void setConversion(const QString& conversion);
+ private:
+ struct TargetToNativeConversionPrivate;
+ TargetToNativeConversionPrivate* m_d;
+ };
+
+ /**
+ * Returns true if the target to C++ custom conversions should
+ * replace the original existing ones, and false if the custom
+ * conversions should be added to the original.
+ */
+ bool replaceOriginalTargetToNativeConversions() const;
+ void setReplaceOriginalTargetToNativeConversions(bool replaceOriginalTargetToNativeConversions);
+
+ typedef QVector<TargetToNativeConversion*> TargetToNativeConversions;
+ bool hasTargetToNativeConversions() const;
+ TargetToNativeConversions& targetToNativeConversions();
+ const TargetToNativeConversions& targetToNativeConversions() const;
+ void addTargetToNativeConversion(const QString& sourceTypeName,
+ const QString& sourceTypeCheck,
+ const QString& conversion = QString());
+private:
+ struct CustomConversionPrivate;
+ CustomConversionPrivate* m_d;
+};
+
+#endif // TYPESYSTEM_H
diff --git a/sources/shiboken2/ApiExtractor/typesystem_enums.h b/sources/shiboken2/ApiExtractor/typesystem_enums.h
new file mode 100644
index 000000000..2d67d7cc5
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typesystem_enums.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TYPESYSTEM_ENUMS_H
+#define TYPESYSTEM_ENUMS_H
+
+namespace TypeSystem
+{
+enum Language {
+ NoLanguage = 0x0000,
+ TargetLangCode = 0x0001,
+ NativeCode = 0x0002,
+ ShellCode = 0x0004,
+ ShellDeclaration = 0x0008,
+ PackageInitializer = 0x0010,
+ DestructorFunction = 0x0020,
+ Constructors = 0x0040,
+ Interface = 0x0080,
+
+ // masks
+ All = TargetLangCode
+ | NativeCode
+ | ShellCode
+ | ShellDeclaration
+ | PackageInitializer
+ | Constructors
+ | Interface
+ | DestructorFunction,
+
+ TargetLangAndNativeCode = TargetLangCode | NativeCode
+};
+
+enum Ownership {
+ InvalidOwnership,
+ DefaultOwnership,
+ TargetLangOwnership,
+ CppOwnership
+};
+
+enum CodeSnipPosition {
+ CodeSnipPositionBeginning,
+ CodeSnipPositionEnd,
+ CodeSnipPositionAfterThis,
+ // QtScript
+ CodeSnipPositionDeclaration,
+ CodeSnipPositionPrototypeInitialization,
+ CodeSnipPositionConstructorInitialization,
+ CodeSnipPositionConstructor,
+ CodeSnipPositionAny
+};
+
+enum DocModificationMode {
+ DocModificationAppend,
+ DocModificationPrepend,
+ DocModificationReplace,
+ DocModificationXPathReplace
+};
+
+} // namespace TypeSystem
+
+#endif // TYPESYSTEM_ENUMS_H
diff --git a/sources/shiboken2/ApiExtractor/typesystem_p.h b/sources/shiboken2/ApiExtractor/typesystem_p.h
new file mode 100644
index 000000000..f2105a631
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typesystem_p.h
@@ -0,0 +1,176 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef TYPESYSTEM_P_H
+#define TYPESYSTEM_P_H
+
+#include <QStack>
+#include "typesystem.h"
+
+QT_FORWARD_DECLARE_CLASS(QXmlStreamAttributes)
+QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
+
+class TypeDatabase;
+class StackElement
+{
+ public:
+ enum ElementType {
+ None = 0x0,
+
+ // Type tags (0x1, ... , 0xff)
+ ObjectTypeEntry = 0x1,
+ ValueTypeEntry = 0x2,
+ InterfaceTypeEntry = 0x3,
+ NamespaceTypeEntry = 0x4,
+ ComplexTypeEntryMask = 0x7,
+
+ // Non-complex type tags (0x8, 0x9, ... , 0xf)
+ PrimitiveTypeEntry = 0x8,
+ EnumTypeEntry = 0x9,
+ ContainerTypeEntry = 0xa,
+ FunctionTypeEntry = 0xb,
+ CustomTypeEntry = 0xc,
+ SmartPointerTypeEntry = 0xd,
+ TypeEntryMask = 0xf,
+
+ // Documentation tags
+ InjectDocumentation = 0x10,
+ ModifyDocumentation = 0x20,
+ DocumentationMask = 0xf0,
+
+ // Simple tags (0x100, 0x200, ... , 0xf00)
+ ExtraIncludes = 0x0100,
+ Include = 0x0200,
+ ModifyFunction = 0x0300,
+ ModifyField = 0x0400,
+ Root = 0x0500,
+ CustomMetaConstructor = 0x0600,
+ CustomMetaDestructor = 0x0700,
+ ArgumentMap = 0x0800,
+ SuppressedWarning = 0x0900,
+ Rejection = 0x0a00,
+ LoadTypesystem = 0x0b00,
+ RejectEnumValue = 0x0c00,
+ Template = 0x0d00,
+ TemplateInstanceEnum = 0x0e00,
+ Replace = 0x0f00,
+ AddFunction = 0x1000,
+ NativeToTarget = 0x1100,
+ TargetToNative = 0x1200,
+ AddConversion = 0x1300,
+ SimpleMask = 0x3f00,
+
+ // Code snip tags (0x1000, 0x2000, ... , 0xf000)
+ InjectCode = 0x4000,
+ InjectCodeInFunction = 0x8000,
+ CodeSnipMask = 0xc000,
+
+ // Function modifier tags (0x010000, 0x020000, ... , 0xf00000)
+ Access = 0x010000,
+ Removal = 0x020000,
+ Rename = 0x040000,
+ ModifyArgument = 0x080000,
+ Thread = 0x100000,
+ FunctionModifiers = 0xff0000,
+
+ // Argument modifier tags (0x01000000 ... 0xf0000000)
+ ConversionRule = 0x01000000,
+ ReplaceType = 0x02000000,
+ ReplaceDefaultExpression = 0x04000000,
+ RemoveArgument = 0x08000000,
+ DefineOwnership = 0x10000000,
+ RemoveDefaultExpression = 0x20000000,
+ NoNullPointers = 0x40000000,
+ ReferenceCount = 0x80000000,
+ ParentOwner = 0x90000000,
+ ArgumentModifiers = 0xff000000
+ };
+
+ StackElement(StackElement *p) : entry(0), type(None), parent(p) { }
+
+ TypeEntry* entry;
+ ElementType type;
+ StackElement *parent;
+
+ union {
+ TemplateInstance* templateInstance;
+ TemplateEntry* templateEntry;
+ CustomFunction* customFunction;
+ } value;
+};
+
+struct StackElementContext
+{
+ CodeSnipList codeSnips;
+ AddedFunctionList addedFunctions;
+ FunctionModificationList functionMods;
+ FieldModificationList fieldMods;
+ DocModificationList docModifications;
+};
+
+class Handler
+{
+public:
+ Handler(TypeDatabase* database, bool generate);
+
+ bool parse(QXmlStreamReader &reader);
+
+private:
+ bool startElement(const QStringRef& localName, const QXmlStreamAttributes& atts);
+ bool handleSmartPointerEntry(StackElement *element,
+ QHash<QString, QString> &attributes,
+ const QString &name,
+ double since);
+ bool endElement(const QStringRef& localName);
+ template <class String> // QString/QStringRef
+ bool characters(const String &ch);
+ void fetchAttributeValues(const QString &name, const QXmlStreamAttributes &atts,
+ QHash<QString, QString> *acceptedAttributes);
+
+ bool importFileElement(const QXmlStreamAttributes &atts);
+ bool convertBoolean(const QString &, const QString &, bool);
+ void addFlags(const QString &name, QString flagName,
+ const QHash<QString, QString> &attributes, double since);
+
+ TypeDatabase* m_database;
+ StackElement* m_current;
+ StackElement* m_currentDroppedEntry;
+ int m_currentDroppedEntryDepth;
+ int m_ignoreDepth;
+ QString m_defaultPackage;
+ QString m_defaultSuperclass;
+ QString m_error;
+ TypeEntry::CodeGeneration m_generate;
+
+ EnumTypeEntry* m_currentEnum;
+ QStack<StackElementContext*> m_contextStack;
+
+ QHash<QString, StackElement::ElementType> tagNames;
+ QString m_currentSignature;
+};
+
+#endif
diff --git a/sources/shiboken2/ApiExtractor/typesystem_typedefs.h b/sources/shiboken2/ApiExtractor/typesystem_typedefs.h
new file mode 100644
index 000000000..4f29deced
--- /dev/null
+++ b/sources/shiboken2/ApiExtractor/typesystem_typedefs.h
@@ -0,0 +1,49 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of PySide2.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TYPESYSTEM_TYPEDEFS_H
+#define TYPESYSTEM_TYPEDEFS_H
+
+#include <QtCore/QHash>
+#include <QtCore/QList>
+#include <QtCore/QVector>
+
+class CodeSnip;
+class DocModification;
+
+struct AddedFunction;
+struct FieldModification;
+struct FunctionModification;
+
+typedef QVector<AddedFunction> AddedFunctionList;
+typedef QVector<CodeSnip> CodeSnipList;
+typedef QVector<DocModification> DocModificationList;
+typedef QVector<FieldModification> FieldModificationList;
+typedef QVector<FunctionModification> FunctionModificationList;
+
+#endif // TYPESYSTEM_TYPEDEFS_H