diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor')
206 files changed, 44044 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..26ae03173 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/CMakeLists.txt @@ -0,0 +1,102 @@ +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 +asttoxml.cpp +fileout.cpp +graph.cpp +reporthandler.cpp +typeparser.cpp +typesystem.cpp +include.cpp +typedatabase.cpp +parser/ast.cpp +parser/binder.cpp +parser/class_compiler.cpp +parser/codemodel.cpp +parser/codemodel_finder.cpp +parser/compiler_utils.cpp +parser/control.cpp +parser/declarator_compiler.cpp +parser/default_visitor.cpp +parser/dumptree.cpp +parser/lexer.cpp +parser/list.cpp +parser/name_compiler.cpp +parser/parser.cpp +parser/smallobject.cpp +parser/tokens.cpp +parser/type_compiler.cpp +parser/visitor.cpp +parser/rpp/builtin-macros.cpp +parser/rpp/preprocessor.cpp +) + +if (NOT DISABLE_DOCSTRINGS) + set(apiextractor_SRC + ${apiextractor_SRC} + docparser.cpp + doxygenparser.cpp + qtdocparser.cpp + ) + set(APIEXTRACTOR_EXTRA_INCLUDES ${LIBXSLT_INCLUDE_DIR} ${LIBXML2_INCLUDE_DIR}) + set(APIEXTRACTOR_EXTRA_LIBRARIES ${LIBXSLT_LIBRARIES} ${LIBXML2_LIBRARIES}) +else() + set(APIEXTRACTOR_EXTRA_INCLUDES "") + set(APIEXTRACTOR_EXTRA_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) + +qt5_add_resources(apiextractor_RCCS_SRC generator.qrc) +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} + ) + +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..e71841ec3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetabuilder.cpp @@ -0,0 +1,3381 @@ +/**************************************************************************** +** +** 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 "parser/ast.h" +#include "parser/binder.h" +#include "parser/control.h" +#include "parser/default_visitor.h" +#include "parser/dumptree.h" +#include "parser/lexer.h" +#include "parser/parser.h" +#include "parser/tokens.h" + +#include <QDebug> +#include <QFile> +#include <QFileInfo> +#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(); + SingleTypeEntryHash entryHash = types->entries(); + QList<TypeEntry*> entries = entryHash.values(); + + foreach (TypeEntry* entry, entries) { + if (!entry) + continue; + if (!entry->isComplex() || entry->codeGeneration() == TypeEntry::GenerateNothing) + continue; + + ComplexTypeEntry* centry = static_cast<ComplexTypeEntry*>(entry); + FunctionModificationList modifications = centry->functionModifications(); + + foreach (const FunctionModification &modification, 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; + + AbstractMetaFunctionList functions = clazz->functions(); + bool found = false; + QStringList possibleSignatures; + foreach (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) +{ + foreach (const ClassModelItem &item, scope->classes()) { + 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(); + foreach (const NamespaceModelItem &n, namespaces) { + if (scope != n) + fixQObjectForScope(dom, types, n); + } +} + +void AbstractMetaBuilderPrivate::sortLists() +{ + foreach (AbstractMetaClass *cls, m_metaClasses) + cls->sortFunctions(); +} + +FileModelItem AbstractMetaBuilderPrivate::buildDom(QIODevice *input) +{ + Q_ASSERT(input); + + if (!input->isOpen() && !input->open(QIODevice::ReadOnly)) + return FileModelItem(); + + QByteArray contents = input->readAll(); + input->close(); + + Control control; + Parser p(&control); + pool __pool; + + TranslationUnitAST* ast = p.parse(contents, contents.size(), &__pool); + + CodeModel model; + Binder binder(&model, p.location()); + return binder.run(ast); +} + +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); + foreach (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 + ReportHandler::setProgressReference(dom->enums()); + foreach (const EnumModelItem &item, dom->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); + foreach (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. + TypeDefList typeDefs = dom->typeDefs(); + ReportHandler::setProgressReference(typeDefs); + foreach (const TypeDefModelItem &typeDef, typeDefs) { + ReportHandler::progress(QLatin1String("Resolving typedefs...")); + AbstractMetaClass* cls = traverseTypeDef(dom, typeDef); + addAbstractMetaClass(cls); + } + + figureOutEnumValues(); + + foreach (const ClassModelItem &item, typeValues) + traverseClassMembers(item); + + foreach (const NamespaceModelItem &item, namespaceTypeValues) + traverseNamespaceMembers(item); + + // Global functions + foreach (const FunctionModelItem &func, dom->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); + foreach (AbstractMetaClass* cls, m_metaClasses) { + ReportHandler::progress(QLatin1String("Fixing class inheritance...")); + if (!cls->isInterface() && !cls->isNamespace()) + setupInheritance(cls); + } + + ReportHandler::setProgressReference(m_metaClasses); + foreach (AbstractMetaClass* cls, 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")); + } + TypeEntryHash allEntries = types->allEntries(); + ReportHandler::progress(QLatin1String("Detecting inconsistencies in typesystem...")); + foreach (QList<TypeEntry*> entries, allEntries) { + foreach (TypeEntry* entry, entries) { + + 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); + foreach (const QString &signature, fte->signatures()) { + bool ok = false; + foreach (AbstractMetaFunction* func, 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 + foreach (AbstractMetaEnum* metaEnum, 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()); + } + + } + } + } + + { + FunctionList hashFunctions = dom->findFunctions(QLatin1String("qHash")); + foreach (const FunctionModelItem &item, hashFunctions) + registerHashFunction(item); + } + + { + FunctionList hashFunctions = dom->findFunctions(QLatin1String("operator<<")); + foreach (const FunctionModelItem &item, hashFunctions) + 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&")); + foreach (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>"))); + + foreach (const FunctionModelItem &item, binaryOperators) + traverseOperatorFunction(item); + } + + { + FunctionList streamOperators = dom->findFunctions(QLatin1String("operator<<")) + + dom->findFunctions(QLatin1String("operator>>")); + foreach (const FunctionModelItem &item, streamOperators) + traverseStreamOperator(item); + } + + figureOutDefaultEnumArguments(); + checkFunctionModifications(); + + // sort all classes topologically + m_metaClasses = classesTopologicalSorted(); + + foreach (AbstractMetaClass* cls, 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. + foreach (const AddedFunction &addedFunc, types->globalUserFunctions()) { + AbstractMetaFunction* metaFunc = traverseFunction(addedFunc); + metaFunc->setFunctionType(AbstractMetaFunction::NormalFunction); + m_globalFunctions << metaFunc; + } + + std::puts(""); +} + +bool AbstractMetaBuilder::build(QIODevice *input) +{ + FileModelItem dom = d->buildDom(input); + const bool result = dom.data() != Q_NULLPTR; + if (result) + d->traverseDom(dom); + return result; +} + +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()); + + ClassList classes = namespaceItem->classes(); + foreach (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(); + foreach (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(); + foreach (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; + + AbstractMetaEnumList enums = metaClass->enums(); + foreach (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; + foreach (AbstractMetaClass *c, m_metaClasses) + figureOutEnumValuesForClass(c, &classes); + + foreach (AbstractMetaEnum* metaEnum, 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() +{ + foreach (AbstractMetaClass* metaClass, m_metaClasses) { + foreach (AbstractMetaFunction* metaFunction, metaClass->functions()) { + foreach (AbstractMetaArgument *arg, metaFunction->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(); + foreach (const EnumeratorModelItem& enumValue, enumItem->enumerators()) { + 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(); + + if (TypeDatabase::instance()->isEnumRejected(className, enumName)) { + if (typeEntry) + typeEntry->setCodeGeneration(TypeEntry::GenerateNothing); + m_rejectedEnums.insert(qualifiedName, 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(); + + foreach (const EnumeratorModelItem &value, enumItem->enumerators()) { + + 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 + foreach(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(); + QList<TypeEntry *> template_args; + template_args.clear(); + for (int i = 0; i < template_parameters.size(); ++i) { + const TemplateParameterModelItem ¶m = 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(); + foreach (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(); + foreach (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(); + foreach (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(); + foreach (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; + + if (TypeDatabase::instance()->isFieldRejected(className, fieldName)) { + m_rejectedFields.insert(qualifiedFieldSignatureWithType(className, field), + 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) +{ + foreach (const VariableModelItem &field, scope_item->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(); + QString castTo = metaFunction->name().remove(QRegExp(QLatin1String("^operator "))).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 QList<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()); + foreach (const FunctionModelItem &function, scopeItem->functions()) { + 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()); + foreach (FunctionModelItem function, scopeItem->functions()) { + // 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); + + foreach (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 + foreach (const AddedFunction &addedFunc, metaClass->typeEntry()->addedFunctions()) + traverseFunction(addedFunc, metaClass); +} + +void AbstractMetaBuilderPrivate::applyFunctionModifications(AbstractMetaFunction *func) +{ + FunctionModificationList mods = func->modifications(func->implementingClass()); + AbstractMetaFunction& funcRef = *func; + foreach (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); + + AbstractMetaClassList interfaces = iface->interfaces(); + foreach (AbstractMetaClass* iface, interfaces) + metaClass->addInterface(iface); + } + } + + return true; +} + +void AbstractMetaBuilderPrivate::traverseEnums(ScopeModelItem scopeItem, + AbstractMetaClass *metaClass, + const QStringList &enumsDeclarations) +{ + EnumList enums = scopeItem->enums(); + foreach (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())); + + + QList<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; + foreach (const FunctionModification &mod, func->modifications(m_currentClass)) { + foreach (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); + } + } + } + + int i = 1; + foreach (AbstractMetaArgument* arg, func->arguments()) { + if (arg->name().isEmpty()) + arg->setName(QLatin1String("arg__") + QString::number(i), false); + ++i; + } +} + +static QString functionSignature(FunctionModelItem functionItem) +{ + QStringList args; + foreach (const ArgumentModelItem &arg, functionItem->arguments()) + args << arg->type().toString(); + return functionItem->name() + QLatin1Char('(') + args.join(QLatin1Char(',')) + QLatin1Char(')'); +} + +static inline QString functionSignatureWithReturnType(FunctionModelItem functionItem) +{ + return functionSignature(functionItem) + + QStringLiteral(" -> ") + functionItem->type().toString(); +} + +static inline QString qualifiedFunctionSignatureWithType(const QString &className, + FunctionModelItem functionItem) +{ + return className + colonColon() + functionSignatureWithReturnType(functionItem); +} + +AbstractMetaFunction *AbstractMetaBuilderPrivate::traverseFunction(FunctionModelItem functionItem) +{ + QString functionName = functionItem->name(); + QString className; + QString rejectedFunctionSignature; + if (m_currentClass) + className = m_currentClass->typeEntry()->qualifiedCppName(); + + if (TypeDatabase::instance()->isFunctionRejected(className, functionName)) { + rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); + m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::GenerationDisabled); + return 0; + } + else if (TypeDatabase::instance()->isFunctionRejected(className, + functionSignature(functionItem))) { + rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); + m_rejectedFunctions.insert(rejectedFunctionSignature, 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 (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::%2', unmatched return type '%3'") + .arg(className, functionItem->name(), + functionItem->type().toString()); + rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); + m_rejectedFunctions.insert(rejectedFunctionSignature, 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); + + bool ok; + AbstractMetaType* metaType = translateType(arg->type(), &ok); + if (!ok) { + Q_ASSERT(metaType == 0); + qCWarning(lcShiboken).noquote().nospace() + << QStringLiteral("skipping function '%1::%2', unmatched parameter type '%3'") + .arg(className, functionItem->name(), arg->type().toString()); + rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); + m_rejectedFunctions.insert(rejectedFunctionSignature, AbstractMetaBuilder::UnmatchedArgumentType); + metaFunction->setInvalid(true); + return metaFunction; + } + + if (metaType == Q_NULLPTR) { + qCWarning(lcShiboken).noquote().nospace() + << QString::fromLatin1("skipping function '%1::%2', 'void' encountered at parameter " + "position %3, but it can only be the the first and only " + "parameter") + .arg(className, functionItem->name()).arg(i); + rejectedFunctionSignature = qualifiedFunctionSignatureWithType(className, functionItem); + 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()) { + QList<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(); + foreach (const QString& candidate, 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) { + foreach (const QString& templateArg, 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()) { + foreach (const AbstractMetaClass* cls, getBaseClasses(m_currentClass)) { + 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) { + QList<TypeEntry *> template_args = m_currentClass->templateArguments(); + foreach (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()); + + foreach (const TypeParser::Info &ta, 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 QRegExp variableNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$")); + if (!variableNameRegExp.exactMatch(stringValue)) { + ok = true; + return 0; + } + + AbstractMetaEnumValue *enumValue = AbstractMetaClass::findEnumValue(m_metaClasses, stringValue); + if (enumValue) { + ok = true; + return enumValue->value(); + } + + foreach (AbstractMetaEnum* metaEnum, m_globalEnums) { + foreach (AbstractMetaEnumValue* ev, metaEnum->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 + QRegExp typeRegEx(QLatin1String("[^<]*[<]([^:]*::).*")); + typeRegEx.indexIn(type->minimalSignature()); + expr = typeRegEx.cap(1) + expr; + } + } else if (type->isContainer() && expr.contains(QLatin1Char('<'))) { + QRegExp typeRegEx(QLatin1String("[^<]*<(.*)>")); + typeRegEx.indexIn(type->minimalSignature()); + QRegExp defaultRegEx(QLatin1String("([^<]*<).*(>[^>]*)")); + defaultRegEx.indexIn(expr); + expr = defaultRegEx.cap(1) + typeRegEx.cap(1) + defaultRegEx.cap(2); + } else { + // Here the default value is supposed to be a constructor, + // a class field, or a constructor receiving a class field + QRegExp defaultRegEx(QLatin1String("([^\\(]*\\(|)([^\\)]*)(\\)|)")); + defaultRegEx.indexIn(expr); + + QString defaultValueCtorName = defaultRegEx.cap(1); + 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. + QRegExp typeRegEx(QLatin1String("^(?:const[\\s]+|)([\\w:]*::|)([A-Za-z_]\\w*)\\s*[&\\*]?$")); + typeRegEx.indexIn(type->minimalSignature()); + + QString typeNamespace = typeRegEx.cap(1); + QString typeCtorName = typeRegEx.cap(2); + if (!typeNamespace.isEmpty() && defaultValueCtorName == typeCtorName) + expr.prepend(typeNamespace); + + // Fix scope if the parameter is a field of the current class + if (implementingClass) { + foreach (const AbstractMetaField* field, implementingClass->fields()) { + if (defaultRegEx.cap(2) == field->name()) { + expr = defaultRegEx.cap(1) + implementingClass->name() + + colonColon() + defaultRegEx.cap(2) + defaultRegEx.cap(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; + foreach (AbstractMetaClass *c, 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; + foreach (const QString& parent, metaClass->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; + foreach (const AbstractMetaClass* cls, getBaseClasses(metaClass)) { + if (ancestorHasPrivateCopyConstructor(cls)) + return true; + } + return false; +} + +AbstractMetaType* AbstractMetaBuilderPrivate::inheritTemplateType(const QList<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) +{ + QList<TypeParser::Info> targs = info.template_instantiations; + QList<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()); + } + + foreach (const TypeParser::Info &i, 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; + foreach (const QString &possibleName, 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(); + foreach (const AbstractMetaFunction* function, templateClass->functions()) { + 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; + } + + foreach (AbstractMetaArgument* argument, function->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); + + foreach (AbstractMetaFunction* f, 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(); + + while (!baseClasses.isEmpty()) { + AbstractMetaClass* currentClass = baseClasses.dequeue(); + baseClasses << currentClass->interfaces(); + if (currentClass->baseClass()) + baseClasses.enqueue(currentClass->baseClass()); + + copyCtor = findCopyCtor(currentClass); + if (copyCtor) { + result = copyCtor->isPublic(); + break; + } + } + } + cls->setHasCloneOperator(result); +} + +void AbstractMetaBuilderPrivate::setupExternalConversion(AbstractMetaClass *cls) +{ + AbstractMetaFunctionList convOps = cls->operatorOverloads(AbstractMetaClass::ConversionOp); + foreach (AbstractMetaFunction* func, convOps) { + if (func->isModifiedRemoved()) + continue; + AbstractMetaClass *metaClass = AbstractMetaClass::findClass(m_metaClasses, func->type()->typeEntry()); + if (!metaClass) + continue; + metaClass->addExternalConversionOperator(func); + } + foreach (AbstractMetaClass* innerClass, cls->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; + foreach (AbstractMetaClass* clazz, classList) { + if (map.contains(clazz->qualifiedCppName())) + continue; + map[clazz->qualifiedCppName()] = i; + reverseMap[i] = clazz; + i++; + } + + Graph graph(map.count()); + + foreach (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 + QRegExp regex1(QLatin1String("\\(.*\\)")); + QRegExp regex2(QLatin1String("::.*")); + foreach (AbstractMetaClass* clazz, classList) { + if (clazz->enclosingClass() && map.contains(clazz->enclosingClass()->qualifiedCppName())) + graph.addEdge(map[clazz->enclosingClass()->qualifiedCppName()], map[clazz->qualifiedCppName()]); + + AbstractMetaClassList bases = getBaseClasses(clazz); + foreach(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()]); + } + + foreach (AbstractMetaFunction* func, clazz->functions()) { + foreach (AbstractMetaArgument* arg, func->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; + foreach(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 { + foreach (int i, 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(); + foreach (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..b4a36a1b6 --- /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(QIODevice* input); + 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..f9eb4bb46 --- /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(QIODevice *input); + 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 QList<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..b861f1b2f --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.cpp @@ -0,0 +1,2786 @@ +/**************************************************************************** +** +** 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 <QStack> + +#include "abstractmetalang.h" +#include "reporthandler.h" +#include "typedatabase.h" +#include "typesystem.h" + +#ifndef QT_NO_DEBUG_STREAM +# include <QtCore/QMetaEnum> +# include <QtCore/QMetaObject> +#endif + +#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.toVector(); + + // 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.toVector(); + } + + 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 +{ + FunctionModificationList mods = modifications(implementingClass()); + foreach (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; + + foreach (const AbstractMetaArgument *arg, 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) { + QList<ReferenceCount> referenceCounts = this->referenceCounts(implementingClass(), i); + foreach (const ReferenceCount &referenceCount, referenceCounts) { + if (referenceCount.action != ReferenceCount::Set) + return true; + } + } + return false; +} + +QString AbstractMetaFunction::marshalledName() const +{ + QString returned = QLatin1String("__qt_") + name(); + AbstractMetaArgumentList arguments = this->arguments(); + foreach (const AbstractMetaArgument *arg, 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()); + + foreach (AbstractMetaArgument *arg, 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; + foreach (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 +QList<ReferenceCount> AbstractMetaFunction::referenceCounts(const AbstractMetaClass *cls, int idx) const +{ + QList<ReferenceCount> returned; + + FunctionModificationList mods = this->modifications(cls); + foreach (const FunctionModification &mod, mods) { + foreach (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 +{ + FunctionModificationList mods = this->modifications(cls); + foreach (const FunctionModification &mod, mods) { + foreach (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 +{ + FunctionModificationList modifications = this->modifications(cls); + foreach (const FunctionModification &modification, modifications) { + foreach (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 +{ + FunctionModificationList modifications = this->modifications(cls); + foreach (const FunctionModification &modification, modifications) { + foreach (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(); + FunctionModificationList modifications = this->modifications(cls); + foreach (const FunctionModification &modification, modifications) { + foreach (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 { + FunctionModificationList modifications = this->modifications(cls); + foreach (const FunctionModification &modification, modifications) { + foreach (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 { + FunctionModificationList modifications = this->modifications(cls); + foreach (const FunctionModification &modification, modifications) { + foreach (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 +{ + FunctionModificationList modifications = this->modifications(declaringClass()); + foreach (const FunctionModification &modification, modifications) { + foreach (const ArgumentModification &argumentModification, modification.argument_mods) { + if (argumentModification.index != key) + continue; + + foreach (const CodeSnip &snip, argumentModification.conversion_rules) { + if (snip.language == language && !snip.code().isEmpty()) + return snip.code(); + } + } + } + + return QString(); +} + +QString AbstractMetaFunction::argumentReplaced(int key) const +{ + FunctionModificationList modifications = this->modifications(declaringClass()); + foreach (const FunctionModification &modification, modifications) { + foreach (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 +{ + FunctionModificationList modifications = this->modifications(declaringClass()); + foreach (const FunctionModification &modification, modifications) { + foreach (const ArgumentModification &argumentModification, modification.argument_mods) { + if (argumentModification.index == key) { + if (argumentModification.removed) + return true; + } + } + } + + return false; +} + +bool AbstractMetaFunction::isVirtualSlot() const +{ + FunctionModificationList modifications = this->modifications(declaringClass()); + foreach (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; + + FunctionModificationList modifications = this->modifications(cls); + foreach (const FunctionModification &modification, modifications) { + foreach (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 +{ + FunctionModificationList modifications = this->modifications(declaringClass()); + foreach (const FunctionModification &modification, modifications) { + if (modification.isDeprecated()) + return true; + } + return false; +} + +bool AbstractMetaFunction::isThread() const +{ + FunctionModificationList modifications = this->modifications(declaringClass()); + foreach (const FunctionModification &modification, modifications) { + if (modification.isThread()) + return true; + } + return false; +} + +bool AbstractMetaFunction::allowThread() const +{ + FunctionModificationList modifications = this->modifications(declaringClass()); + foreach (const FunctionModification &modification, modifications) { + if (modification.allowThread()) + return true; + } + return false; +} + + +TypeSystem::Ownership AbstractMetaFunction::ownership(const AbstractMetaClass *cls, TypeSystem::Language language, int key) const +{ + FunctionModificationList modifications = this->modifications(cls); + foreach (const FunctionModification &modification, modifications) { + foreach (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 +{ + FunctionModificationList modifications = this->modifications(cls); + foreach (const FunctionModification &modification, modifications) { + if ((modification.removal & language) == language) + return true; + } + + return false; + +} + +QString AbstractMetaFunction::typeReplaced(int key) const +{ + FunctionModificationList modifications = this->modifications(declaringClass()); + foreach (const FunctionModification &modification, modifications) { + foreach (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; + foreach (const AbstractMetaClass* interface, implementor->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 +{ + foreach (const FunctionModification &mod, modifications(ownerClass())) { + if (mod.isCodeInjection()) + return true; + } + return false; +} + +CodeSnipList AbstractMetaFunction::injectedCodeSnips(TypeSystem::CodeSnipPosition position, TypeSystem::Language language) const +{ + CodeSnipList result; + foreach (const FunctionModification &mod, modifications(ownerClass())) { + if (mod.isCodeInjection()) { + QList<CodeSnip>::const_iterator it = mod.snips.constBegin(); + for (;it != mod.snips.constEnd(); ++it) { + if ((it->language & language) && (it->position == position || position == TypeSystem::CodeSnipPositionAny)) + result << *it; + } + } + } + return result; +} + +bool AbstractMetaFunction::hasSignatureModifications() const +{ + foreach (const FunctionModification &mod, modifications()) { + if (mod.isRenameModifier()) + return true; + foreach (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 QRegExp opRegEx(QLatin1String("^operator(?:\\s+(?:const|volatile))?\\s+(\\w+\\s*)&?$")); + return opRegEx.indexIn(funcName) > -1; +} + +bool AbstractMetaFunction::isOperatorOverload(QString funcName) +{ + if (isConversionOperator(funcName)) + return true; + + static QRegExp opRegEx(QLatin1String("^operator([+\\-\\*/%=&\\|\\^\\<>!][=]?" + "|\\+\\+|\\-\\-|&&|\\|\\||<<[=]?|>>[=]?|~" + "|\\[\\]|\\s+delete\\[?\\]?" + "|\\(\\)" + "|\\s+new\\[?\\]?)$")); + return opRegEx.indexIn(funcName) > -1; +} + +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()) { + FunctionModificationList mods = modifications(implementingClass()); + foreach (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()) { + foreach (AbstractMetaType* inst, templateBaseClassInstantiations()) + delete inst; + } +} + +/******************************************************************************* + * 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()); + + foreach (AbstractMetaFunction *function, functions()) { + if (!function->isConstructor()) + iface->addFunction(function->copy()); + } + +// iface->setEnums(enums()); +// setEnums(AbstractMetaEnumList()); + + foreach (const AbstractMetaField *field, 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; + AbstractMetaFunctionList functions = this->functions(); + foreach (AbstractMetaFunction *function, 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 +{ + AbstractMetaFunctionList list = functionsInShellClass(); + + AbstractMetaFunctionList returned; + foreach (AbstractMetaFunction *f, list) { + if (!f->isFinalInCpp() || f->isVirtualSlot()) + returned += f; + } + + return returned; +} + +AbstractMetaFunctionList AbstractMetaClass::implicitConversions() const +{ + if (!hasCloneOperator() && !hasExternalConversionOperators()) + return AbstractMetaFunctionList(); + + AbstractMetaFunctionList returned; + AbstractMetaFunctionList list = queryFunctions(Constructors); + + list.append(externalConversionOperators()); + + // Exclude anything that uses rvalue references, be it a move + // constructor "QPolygon(QPolygon &&)" or something else like + // "QPolygon(QVector<QPoint> &&)". + foreach (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 +{ + AbstractMetaFunctionList list = queryFunctions(OperatorOverloads | Visible); + AbstractMetaFunctionList returned; + foreach (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 +{ + foreach (const AbstractMetaFunction *f, m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isOperatorOverload() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasArithmeticOperatorOverload() const +{ + foreach (const AbstractMetaFunction *f, m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isArithmeticOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasBitwiseOperatorOverload() const +{ + foreach (const AbstractMetaFunction *f, m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isBitwiseOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasComparisonOperatorOverload() const +{ + foreach (const AbstractMetaFunction *f, m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isComparisonOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasLogicalOperatorOverload() const +{ + foreach (const AbstractMetaFunction *f, m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isLogicalOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasSubscriptOperatorOverload() const +{ + foreach (const AbstractMetaFunction *f, m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isSubscriptOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasAssignmentOperatorOverload() const +{ + foreach (const AbstractMetaFunction *f, m_functions) { + if (f->ownerClass() == f->implementingClass() && f->isAssignmentOperator() && !f->isPrivate()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasConversionOperatorOverload() const +{ + foreach (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; + foreach (AbstractMetaFunction *f, 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) { + foreach (AbstractMetaFunction *final_function, 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 +{ + foreach (const AbstractMetaField *field, fields()) { + if (field->getter() || field->setter()) + return true; + } + + return false; +} + +bool AbstractMetaClass::hasDefaultToStringFunction() const +{ + foreach (AbstractMetaFunction *f, queryFunctionsByName(QLatin1String("toString"))) { + 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; + + foreach (const AbstractMetaFunction *f, 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 +{ + foreach (const AbstractMetaFunction *f, functions()) { + if (f->name() == functionName) + return f; + } + return 0; +} + +bool AbstractMetaClass::hasProtectedFunctions() const +{ + foreach (AbstractMetaFunction *func, m_functions) { + if (func->isProtected()) + return true; + } + return false; +} + +bool AbstractMetaClass::hasProtectedFields() const +{ + foreach (const AbstractMetaField *field, 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) +{ + foreach (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 +{ + FieldModificationList mods = modifications(); + foreach (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); + + FieldModificationList mods = g->modifications(); + foreach (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 +{ + FieldModificationList mods = enclosingClass()->typeEntry()->fieldModifications(); + FieldModificationList returned; + + foreach (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 +{ + foreach (const AbstractMetaFunction* ctor, queryFunctions(Constructors)) { + if (ctor->functionType() == AbstractMetaFunction::CopyConstructorFunction) + return true; + } + return false; +} + +bool AbstractMetaClass::hasPrivateCopyConstructor() const +{ + foreach (const AbstractMetaFunction* ctor, queryFunctions(Constructors)) { + 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; + + foreach (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 + foreach (AbstractMetaFunction *function, interface->functions()) + 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. + FunctionModificationList mods = function->modifications(interface); + foreach (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; + foreach (const AbstractMetaClass* interface, interfaces) { + if (interface) + m_isPolymorphic |= interface->isPolymorphic(); + } +} + + +AbstractMetaEnum *AbstractMetaClass::findEnum(const QString &enumName) +{ + foreach (AbstractMetaEnum *e, 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) +{ + foreach (AbstractMetaEnum *e, m_enums) { + if (e != meta_enum) + continue; + foreach (AbstractMetaEnumValue *v, e->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) +{ + foreach (AbstractMetaEnum *e, m_enums) { + foreach (AbstractMetaEnumValue *v, e->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()) { + AbstractMetaTypeList instantiations = type->instantiations(); + foreach (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()); + + AbstractMetaArgumentList arguments = meta_function->arguments(); + foreach (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; + FunctionModificationList mods = sf->modifications(sf->implementingClass()); + foreach (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; + } + + foreach (AbstractMetaFunction *f, funcsToAdd) + funcs << f->copy(); + + if (superClass) + superClass = superClass->baseClass(); + else + iface_idx++; + } + + bool hasPrivateConstructors = false; + bool hasPublicConstructors = false; + foreach (AbstractMetaFunction *func, funcs) { + FunctionModificationList mods = func->modifications(this); + foreach (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; + } + + foreach (AbstractMetaFunction *f1, funcs) { + foreach (AbstractMetaFunction *f2, 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 *AbstractMetaEnumValueList::find(const QString &name) const +{ + for (int i = 0; i < size(); ++i) { + if (name == at(i)->name()) + return at(i); + } + return 0; +} + +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); + } + + foreach (AbstractMetaClass* metaClass, classes) { + foreach(AbstractMetaEnum* metaEnum, metaClass->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; + + foreach (AbstractMetaClass *c, classes) { + if (c->qualifiedCppName() == name) + return c; + } + + foreach (AbstractMetaClass *c, classes) { + if (c->fullName() == name) + return c; + } + + foreach (AbstractMetaClass *c, classes) { + if (c->name() == name) + return c; + } + + return 0; +} + +AbstractMetaClass *AbstractMetaClass::findClass(const AbstractMetaClassList &classes, + const TypeEntry* typeEntry) +{ + foreach (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..26702d3a2 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetalang.h @@ -0,0 +1,1983 @@ +/**************************************************************************** +** +** 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 + { + foreach (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; + QList<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 AbstractMetaEnumValueList : public QList<AbstractMetaEnumValue *> +{ +public: + AbstractMetaEnumValue *find(const QString &name) const; +}; + +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; + + + QList<TypeEntry *> templateArguments() const + { + return m_templateArgs; + } + + void setTemplateArguments(const QList<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; + } + + QList<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; + QList<QPropertySpec *> m_propertySpecs; + AbstractMetaClassList m_innerClasses; + + AbstractMetaFunctionList m_externalConversionOperators; + + QStringList m_baseClassNames; + QList<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..dd6573b78 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/abstractmetalang_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 ABSTRACTMETALANG_TYPEDEFS_H +#define ABSTRACTMETALANG_TYPEDEFS_H + +#include <QtCore/QList> + +class AbstractMetaClass; +class AbstractMetaField; +class AbstractMetaArgument; +class AbstractMetaEnum; +class AbstractMetaEnumValueList; +class AbstractMetaFunction; +class AbstractMetaType; + +typedef QList<AbstractMetaArgument *> AbstractMetaArgumentList; +typedef QList<AbstractMetaClass *> AbstractMetaClassList; +typedef QList<AbstractMetaEnum *> AbstractMetaEnumList; +typedef QList<AbstractMetaField *> AbstractMetaFieldList; +typedef QList<AbstractMetaFunction *> AbstractMetaFunctionList; +typedef QList<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..371ccf559 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/apiextractor.cpp @@ -0,0 +1,356 @@ +/**************************************************************************** +** +** 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 <iostream> + +#include "reporthandler.h" +#include "typesystem.h" +#include "fileout.h" +#include "parser/rpp/pp.h" +#include "abstractmetabuilder.h" +#include "typedatabase.h" +#include "typesystem.h" + +static bool preprocess(const QString& sourceFile, + QFile& targetFile, + const QStringList& includes); + +ApiExtractor::ApiExtractor() : m_builder(0) +{ + static bool qrcInitialized = false; + if (!qrcInitialized) + Q_INIT_RESOURCE(generator); + // 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) +{ + foreach (const QString &path, paths) + addTypesystemSearchPath(path); +} + +void ApiExtractor::addIncludePath(const QString& path) +{ + m_includePaths << path; +} + +void ApiExtractor::addIncludePath(const QStringList& 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; + foreach (const AbstractMetaClass* metaClass, metaClasses) { + foreach (const AbstractMetaEnum* metaEnum, metaClass->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; + foreach (AbstractMetaEnum* metaEnum, m_builder->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; + } + + QTemporaryFile ppFile; +#ifndef NDEBUG + ppFile.setAutoRemove(false); +#endif + // make sure that a tempfile can be written + if (!ppFile.open()) { + std::cerr << "could not create tempfile in " << qPrintable(QDir::tempPath()); + return false; + } + + // run rpp pre-processor + if (!preprocess(m_cppFileName, ppFile, m_includePaths)) { + std::cerr << "Preprocessor failed on file: " << qPrintable(m_cppFileName); + return false; + } + ppFile.seek(0); + m_builder = new AbstractMetaBuilder; + m_builder->setLogDirectory(m_logDirectory); + m_builder->setGlobalHeader(m_cppFileName); + m_builder->build(&ppFile); + + return true; +} + +static bool preprocess(const QString& sourceFile, + QFile& targetFile, + const QStringList& includes) +{ + rpp::pp_environment env; + rpp::pp preprocess(env); + + rpp::pp_null_output_iterator null_out; + + const char *ppconfig = ":/trolltech/generator/pp-qt-configuration"; + + const QString fileName = QLatin1String(ppconfig); + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) { + std::cerr << "Preprocessor configuration file not found " << ppconfig << std::endl; + return false; + } + + QByteArray ba = file.readAll(); + file.close(); + preprocess.operator()(ba.constData(), ba.constData() + ba.size(), null_out); + + preprocess.push_include_path("."); + foreach (const QString &include, includes) + preprocess.push_include_path(QDir::toNativeSeparators(include).toStdString()); + preprocess.push_include_path("/usr/include"); + + QString currentDir = QDir::current().absolutePath(); + QFileInfo sourceInfo(sourceFile); + if (!sourceInfo.exists()) { + std::cerr << "File not found " << qPrintable(sourceFile) << std::endl; + return false; + } + QDir::setCurrent(sourceInfo.absolutePath()); + + std::string result; + result.reserve(20 * 1024); // 20K + + result += "# 1 \"builtins\"\n"; + result += "# 1 \""; + result += sourceFile.toStdString(); + result += "\"\n"; + + preprocess.file(sourceInfo.fileName().toStdString(), + rpp::pp_output_iterator<std::string> (result)); + + QDir::setCurrent(currentDir); + + if (!targetFile.open(QIODevice::ReadWrite | QIODevice::Text)) { + std::cerr << "Failed to write preprocessed file: " << qPrintable(targetFile.fileName()) << std::endl; + return false; + } + + targetFile.write(result.c_str(), result.length()); + return true; +} + +#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..1080ff507 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/apiextractor.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** 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 "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 QString& path); + void addIncludePath(const QStringList& paths); + QStringList 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; + QStringList 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/asttoxml.cpp b/sources/shiboken2/ApiExtractor/asttoxml.cpp new file mode 100644 index 000000000..7a2f1261e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/asttoxml.cpp @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** 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 "asttoxml.h" +#include "parser/control.h" +#include "parser/parser.h" +#include "parser/binder.h" + + +#include <QtCore/QXmlStreamWriter> +#include <QtCore/QTextStream> +#include <QtCore/QTextCodec> +#include <QtCore/QFile> + +typedef QHash<QString, EnumModelItem> EnumMap; +typedef QHash<QString, FunctionModelItem> FunctionModelItemMap; +typedef QHash<QString, ClassModelItem> ClassModelItemMap; +typedef QHash<QString, NamespaceModelItem> NamespaceModelItemMap; + +void astToXML(QString name) +{ + QFile file(name); + + if (!file.open(QFile::ReadOnly)) + return; + + QTextStream stream(&file); + stream.setCodec(QTextCodec::codecForName("UTF-8")); + QByteArray contents = stream.readAll().toUtf8(); + file.close(); + + Control control; + Parser p(&control); + pool __pool; + + TranslationUnitAST *ast = p.parse(contents, contents.size(), &__pool); + + CodeModel model; + Binder binder(&model, p.location()); + FileModelItem dom = binder.run(ast); + + QFile outputFile; + if (!outputFile.open(stdout, QIODevice::WriteOnly)) + return; + + QXmlStreamWriter s(&outputFile); + s.setAutoFormatting(true); + + s.writeStartElement(QLatin1String("code")); + + const NamespaceList &namespaces = dom->namespaces(); + foreach (const NamespaceModelItem &n, namespaces) + writeOutNamespace(s, n); + + const ClassList &classList = dom->classes(); + foreach (const ClassModelItem &c, classList) + writeOutClass(s, c); + + s.writeEndElement(); +} + +void writeOutNamespace(QXmlStreamWriter &s, const NamespaceModelItem &item) +{ + s.writeStartElement(QLatin1String("namespace")); + s.writeAttribute(QLatin1String("name"), item->name()); + + const NamespaceList &namespaces = item->namespaces(); + foreach (const NamespaceModelItem &n, namespaces) + writeOutNamespace(s, n); + + const ClassList &classList = item->classes(); + foreach (const ClassModelItem &c, classList) + writeOutClass(s, c); + + const EnumList &enums = item->enums(); + foreach (const EnumModelItem &e, enums) + writeOutEnum(s, e); + + s.writeEndElement(); +} + +void writeOutEnum(QXmlStreamWriter &s, const EnumModelItem &item) +{ + QString qualifiedName = item->qualifiedName().join(QLatin1String("::")); + s.writeStartElement(QLatin1String("enum")); + s.writeAttribute(QLatin1String("name"), qualifiedName); + + EnumeratorList enumList = item->enumerators(); + for (int i = 0; i < enumList.size() ; i++) { + s.writeStartElement(QLatin1String("enumerator")); + if (!enumList[i]->value().isEmpty()) + s.writeAttribute(QLatin1String("value"), enumList[i]->value()); + s.writeCharacters(enumList[i]->name()); + + s.writeEndElement(); + } + s.writeEndElement(); +} + +void writeOutFunction(QXmlStreamWriter &s, const FunctionModelItem &item) +{ + QString qualifiedName = item->qualifiedName().join(QLatin1String("::")); + s.writeStartElement(QLatin1String("function")); + s.writeAttribute(QLatin1String("name"), qualifiedName); + + ArgumentList arguments = item->arguments(); + for (int i = 0; i < arguments.size() ; i++) { + s.writeStartElement(QLatin1String("argument")); + s.writeAttribute(QLatin1String("type"), arguments[i]->type().qualifiedName().join(QLatin1String("::"))); + s.writeEndElement(); + } + s.writeEndElement(); +} + +void writeOutClass(QXmlStreamWriter &s, const ClassModelItem &item) +{ + QString qualifiedName = item->qualifiedName().join(QLatin1String("::")); + s.writeStartElement(QLatin1String("class")); + s.writeAttribute(QLatin1String("name"), qualifiedName); + + const EnumList &enums = item->enums(); + foreach (const EnumModelItem &e, enums) + writeOutEnum(s, e); + + const FunctionList &functionList = item->functions(); + foreach (const FunctionModelItem &func, functionList) + writeOutFunction(s, func); + + const ClassList &classList = item->classes(); + foreach (const ClassModelItem &c, classList) + writeOutClass(s, c); + + s.writeEndElement(); +} + diff --git a/sources/shiboken2/ApiExtractor/asttoxml.h b/sources/shiboken2/ApiExtractor/asttoxml.h new file mode 100644 index 000000000..ed2a04833 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/asttoxml.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** 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 ASTTOXML +#define ASTTOXML + +#include "parser/codemodel_fwd.h" + +#include <QtCore/QString> + +QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter) + +void astToXML(const QString name); +void writeOutNamespace(QXmlStreamWriter &s, const NamespaceModelItem &item); +void writeOutEnum(QXmlStreamWriter &s, const EnumModelItem &item); +void writeOutFunction(QXmlStreamWriter &s, const FunctionModelItem &item); +void writeOutClass(QXmlStreamWriter &s, const ClassModelItem &item); + + +#endif // ASTTOXML 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 Binary files differnew file mode 100644 index 000000000..843e7e2c5 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_header.png diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg Binary files differnew file mode 100644 index 000000000..4229ae8db --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/bg_topo.jpg diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png Binary files differnew file mode 100644 index 000000000..b45830e00 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/fakebar.png diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg Binary files differnew file mode 100644 index 000000000..2a1fbe7a1 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_indt.jpg diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png Binary files differnew file mode 100644 index 000000000..51e868d6e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_openbossa.png diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg Binary files differnew file mode 100644 index 000000000..cd474efba --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_python.jpg diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png Binary files differnew file mode 100644 index 000000000..37800f454 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/logo_qt.png 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 Binary files differnew file mode 100644 index 000000000..076c1057c --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/pysidelogo.png diff --git a/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png Binary files differnew file mode 100644 index 000000000..4036733a7 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/doc/_themes/pysidedocs/static/relbar_bg.png 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..4ec1da299 --- /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("&")); + escapedQuery.replace(QLatin1Char('<'), QLatin1String("<")); + 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; + foreach (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" + ); + foreach (DocModification mod, mods) { + if (mod.mode() == TypeSystem::DocModificationXPathReplace) { + QString xpath = mod.xpath(); + xpath.replace(QLatin1Char('"'), QLatin1String(""")); + 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..f7d868f8d --- /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 + AbstractMetaFunctionList funcs = metaClass->functionsInTargetLang(); + foreach (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; + foreach (AbstractMetaArgument* arg, func->arguments()) { + QString type; + 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 + AbstractMetaFieldList fields = metaClass->fields(); + foreach (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 + AbstractMetaEnumList enums = metaClass->enums(); + foreach (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..7314cfe3b --- /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() {} + virtual void fillDocumentation(AbstractMetaClass *metaClass); + virtual Documentation retrieveModuleDocumentation(); + virtual Documentation retrieveModuleDocumentation(const QString& name); +}; + +#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/generator.qrc b/sources/shiboken2/ApiExtractor/generator.qrc new file mode 100644 index 000000000..2d82b37cb --- /dev/null +++ b/sources/shiboken2/ApiExtractor/generator.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource prefix="/trolltech/generator/"> +<file alias="pp-qt-configuration">parser/rpp/pp-qt-configuration</file> +</qresource> +</RCC> 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/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..e4ff5b309 --- /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 <QList> + +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 QList<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/ast.cpp b/sources/shiboken2/ApiExtractor/parser/ast.cpp new file mode 100644 index 000000000..a744704fe --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/ast.cpp @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** 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 "ast.h" +#include "lexer.h" + +QString AST::toString(TokenStream *stream) const +{ + const Token &tk = stream->token((int) start_token); + const Token &end_tk = stream->token((int) end_token); + return QString::fromLatin1(tk.text + tk.position, end_tk.position - tk.position); +} diff --git a/sources/shiboken2/ApiExtractor/parser/ast.h b/sources/shiboken2/ApiExtractor/parser/ast.h new file mode 100644 index 000000000..7640b7c38 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/ast.h @@ -0,0 +1,884 @@ +/**************************************************************************** +** +** 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 AST_H +#define AST_H + +#include "smallobject.h" +#include "list.h" + +#include <QString> + +#define DECLARE_AST_NODE(k) \ + enum { __node_kind = Kind_##k }; + +class TokenStream; + +struct AccessSpecifierAST; +struct AsmDefinitionAST; +struct BaseClauseAST; +struct BaseSpecifierAST; +struct BinaryExpressionAST; +struct CastExpressionAST; +struct ClassMemberAccessAST; +struct ClassSpecifierAST; +struct CompoundStatementAST; +struct ConditionAST; +struct ConditionalExpressionAST; +struct CppCastExpressionAST; +struct CtorInitializerAST; +struct DeclarationAST; +struct DeclarationStatementAST; +struct DeclaratorAST; +struct DeleteExpressionAST; +struct DoStatementAST; +struct ElaboratedTypeSpecifierAST; +struct EnumSpecifierAST; +struct EnumeratorAST; +struct ExceptionSpecificationAST; +struct ExpressionAST; +struct ExpressionOrDeclarationStatementAST; +struct ExpressionStatementAST; +struct ForStatementAST; +struct FunctionCallAST; +struct FunctionDefinitionAST; +struct IfStatementAST; +struct IncrDecrExpressionAST; +struct InitDeclaratorAST; +struct InitializerAST; +struct InitializerClauseAST; +struct LabeledStatementAST; +struct LinkageBodyAST; +struct LinkageSpecificationAST; +struct MemInitializerAST; +struct NameAST; +struct NamespaceAST; +struct NamespaceAliasDefinitionAST; +struct NewDeclaratorAST; +struct NewExpressionAST; +struct NewInitializerAST; +struct NewTypeIdAST; +struct OperatorAST; +struct OperatorFunctionIdAST; +struct ParameterDeclarationAST; +struct ParameterDeclarationClauseAST; +struct PostfixExpressionAST; +struct PrimaryExpressionAST; +struct PtrOperatorAST; +struct PtrToMemberAST; +struct ReturnStatementAST; +struct SimpleDeclarationAST; +struct SimpleTypeSpecifierAST; +struct SizeofExpressionAST; +struct StatementAST; +struct StringLiteralAST; +struct SubscriptExpressionAST; +struct SwitchStatementAST; +struct TemplateArgumentAST; +struct TemplateDeclarationAST; +struct TemplateParameterAST; +struct ThrowExpressionAST; +struct TranslationUnitAST; +struct TryBlockStatementAST; +struct TypeIdAST; +struct TypeIdentificationAST; +struct TypeParameterAST; +struct TypeSpecifierAST; +struct TypedefAST; +struct UnaryExpressionAST; +struct UnqualifiedNameAST; +struct UsingAST; +struct UsingDirectiveAST; +struct WhileStatementAST; +struct WinDeclSpecAST; +struct QPropertyAST; +struct QEnumsAST; + +struct AST +{ + enum NODE_KIND { + Kind_UNKNOWN = 0, + + Kind_AccessSpecifier, + Kind_AsmDefinition, + Kind_BaseClause, + Kind_BaseSpecifier, + Kind_BinaryExpression, + Kind_CastExpression, + Kind_ClassMemberAccess, + Kind_ClassSpecifier, + Kind_CompoundStatement, + Kind_Condition, + Kind_ConditionalExpression, + Kind_CppCastExpression, + Kind_CtorInitializer, + Kind_DeclarationStatement, + Kind_Declarator, + Kind_DeleteExpression, + Kind_DoStatement, + Kind_ElaboratedTypeSpecifier, + Kind_EnumSpecifier, + Kind_Enumerator, + Kind_ExceptionSpecification, + Kind_ExpressionOrDeclarationStatement, + Kind_ExpressionStatement, + Kind_ForStatement, + Kind_FunctionCall, + Kind_FunctionDefinition, + Kind_IfStatement, + Kind_IncrDecrExpression, + Kind_InitDeclarator, + Kind_Initializer, + Kind_InitializerClause, + Kind_LabeledStatement, + Kind_LinkageBody, + Kind_LinkageSpecification, + Kind_MemInitializer, + Kind_Name, + Kind_Namespace, + Kind_NamespaceAliasDefinition, + Kind_NewDeclarator, + Kind_NewExpression, + Kind_NewInitializer, + Kind_NewTypeId, + Kind_Operator, + Kind_OperatorFunctionId, + Kind_ParameterDeclaration, + Kind_ParameterDeclarationClause, + Kind_PostfixExpression, + Kind_PrimaryExpression, + Kind_PtrOperator, + Kind_PtrToMember, + Kind_ReturnStatement, + Kind_SimpleDeclaration, + Kind_SimpleTypeSpecifier, + Kind_SizeofExpression, + Kind_StringLiteral, + Kind_SubscriptExpression, + Kind_SwitchStatement, + Kind_TemplateArgument, + Kind_TemplateDeclaration, + Kind_TemplateParameter, + Kind_ThrowExpression, + Kind_TranslationUnit, + Kind_TryBlockStatement, + Kind_TypeId, + Kind_TypeIdentification, + Kind_TypeParameter, + Kind_Typedef, + Kind_UnaryExpression, + Kind_UnqualifiedName, + Kind_Using, + Kind_UsingDirective, + Kind_WhileStatement, + Kind_WinDeclSpec, + Kind_QPropertyAST, + Kind_ForwardDeclarationSpecifier, + Kind_QEnumsAST, + + NODE_KIND_COUNT + }; + + QString toString(TokenStream *stream) const; + + int kind; + + std::size_t start_token; + std::size_t end_token; +}; + +struct TypeSpecifierAST: public AST +{ + const ListNode<std::size_t> *cv; +}; + +struct StatementAST: public AST +{ +}; + +struct ExpressionAST: public AST +{ +}; + +struct DeclarationAST: public AST +{ +}; + +struct AccessSpecifierAST: public DeclarationAST +{ + DECLARE_AST_NODE(AccessSpecifier) + + const ListNode<std::size_t> *specs; +}; + +struct AsmDefinitionAST: public DeclarationAST +{ + DECLARE_AST_NODE(AsmDefinition) + + const ListNode<std::size_t> *cv; +}; + +struct BaseClauseAST: public AST +{ // ### kill me + DECLARE_AST_NODE(BaseClause) + + const ListNode<BaseSpecifierAST*> *base_specifiers; +}; + +struct BaseSpecifierAST: public AST +{ + DECLARE_AST_NODE(BaseSpecifier) + + std::size_t virt; + std::size_t access_specifier; + NameAST *name; +}; + +struct BinaryExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(BinaryExpression) + + std::size_t op; + ExpressionAST *left_expression; + ExpressionAST *right_expression; +}; + +struct CastExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(CastExpression) + + TypeIdAST *type_id; + ExpressionAST *expression; +}; + +struct ClassMemberAccessAST: public ExpressionAST +{ + DECLARE_AST_NODE(ClassMemberAccess) + + std::size_t op; + NameAST *name; +}; + +struct ClassSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(ClassSpecifier) + + WinDeclSpecAST *win_decl_specifiers; + std::size_t class_key; + NameAST *name; + BaseClauseAST *base_clause; + const ListNode<DeclarationAST*> *member_specs; +}; + +struct ForwardDeclarationSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(ForwardDeclarationSpecifier) + + std::size_t class_key; + NameAST *name; + BaseClauseAST *base_clause; +}; + +struct CompoundStatementAST: public StatementAST +{ + DECLARE_AST_NODE(CompoundStatement) + + const ListNode<StatementAST*> *statements; +}; + +struct ConditionAST: public AST +{ + DECLARE_AST_NODE(Condition) + + TypeSpecifierAST *type_specifier; + DeclaratorAST *declarator; + ExpressionAST *expression; +}; + +struct ConditionalExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(ConditionalExpression) + + ExpressionAST *condition; + ExpressionAST *left_expression; + ExpressionAST *right_expression; +}; + +struct CppCastExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(CppCastExpression) + + std::size_t op; + TypeIdAST *type_id; + ExpressionAST *expression; + const ListNode<ExpressionAST*> *sub_expressions; +}; + +struct CtorInitializerAST: public AST +{ + DECLARE_AST_NODE(CtorInitializer) + + std::size_t colon; + const ListNode<MemInitializerAST*> *member_initializers; +}; + +struct DeclarationStatementAST: public StatementAST +{ + DECLARE_AST_NODE(DeclarationStatement) + + DeclarationAST *declaration; +}; + +struct DeclaratorAST: public AST +{ + DECLARE_AST_NODE(Declarator) + + const ListNode<PtrOperatorAST*> *ptr_ops; + DeclaratorAST *sub_declarator; + NameAST *id; + ExpressionAST *bit_expression; + const ListNode<ExpressionAST*> *array_dimensions; + ParameterDeclarationClauseAST *parameter_declaration_clause; + const ListNode<std::size_t> *fun_cv; + ExceptionSpecificationAST *exception_spec; +}; + +struct DeleteExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(DeleteExpression) + + std::size_t scope_token; + std::size_t delete_token; + std::size_t lbracket_token; + std::size_t rbracket_token; + ExpressionAST *expression; +}; + +struct DoStatementAST: public StatementAST +{ + DECLARE_AST_NODE(DoStatement) + + StatementAST *statement; + ExpressionAST *expression; +}; + +struct ElaboratedTypeSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(ElaboratedTypeSpecifier) + + std::size_t type; + NameAST *name; +}; + +struct EnumSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(EnumSpecifier) + + NameAST *name; + const ListNode<EnumeratorAST*> *enumerators; +}; + +struct EnumeratorAST: public AST +{ + DECLARE_AST_NODE(Enumerator) + + std::size_t id; + ExpressionAST *expression; +}; + +struct ExceptionSpecificationAST: public AST +{ + DECLARE_AST_NODE(ExceptionSpecification) + + std::size_t ellipsis; + const ListNode<TypeIdAST*> *type_ids; +}; + +struct ExpressionOrDeclarationStatementAST: public StatementAST +{ + DECLARE_AST_NODE(ExpressionOrDeclarationStatement) + + StatementAST *expression; + StatementAST *declaration; +}; + +struct ExpressionStatementAST: public StatementAST +{ + DECLARE_AST_NODE(ExpressionStatement) + + ExpressionAST *expression; +}; + +struct FunctionCallAST: public ExpressionAST +{ + DECLARE_AST_NODE(FunctionCall) + + ExpressionAST *arguments; +}; + +struct FunctionDefinitionAST: public DeclarationAST +{ + DECLARE_AST_NODE(FunctionDefinition) + + const ListNode<std::size_t> *storage_specifiers; + const ListNode<std::size_t> *function_specifiers; + TypeSpecifierAST *type_specifier; + InitDeclaratorAST *init_declarator; + StatementAST *function_body; + WinDeclSpecAST *win_decl_specifiers; +}; + +struct ForStatementAST: public StatementAST +{ + DECLARE_AST_NODE(ForStatement) + + StatementAST *init_statement; + ConditionAST *condition; + ExpressionAST *expression; + StatementAST *statement; +}; + +struct IfStatementAST: public StatementAST +{ + DECLARE_AST_NODE(IfStatement) + + ConditionAST *condition; + StatementAST *statement; + StatementAST *else_statement; +}; + +struct IncrDecrExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(IncrDecrExpression) + + std::size_t op; +}; + +struct InitDeclaratorAST: public AST +{ + DECLARE_AST_NODE(InitDeclarator) + + DeclaratorAST *declarator; + InitializerAST *initializer; +}; + +struct InitializerAST: public AST +{ + DECLARE_AST_NODE(Initializer) + + InitializerClauseAST *initializer_clause; + ExpressionAST *expression; +}; + +struct InitializerClauseAST: public AST +{ + DECLARE_AST_NODE(InitializerClause) + + ExpressionAST *expression; +}; + +struct LabeledStatementAST: public StatementAST +{ + DECLARE_AST_NODE(LabeledStatement) +}; + +struct LinkageBodyAST: public AST +{ + DECLARE_AST_NODE(LinkageBody) + + const ListNode<DeclarationAST*> *declarations; +}; + +struct LinkageSpecificationAST: public DeclarationAST +{ + DECLARE_AST_NODE(LinkageSpecification) + + std::size_t extern_type; + LinkageBodyAST *linkage_body; + DeclarationAST *declaration; +}; + +struct MemInitializerAST: public AST +{ + DECLARE_AST_NODE(MemInitializer) + + NameAST *initializer_id; + ExpressionAST *expression; +}; + +struct NameAST: public AST +{ + DECLARE_AST_NODE(Name) + + bool global; + const ListNode<UnqualifiedNameAST*> *qualified_names; + UnqualifiedNameAST *unqualified_name; +}; + +struct NamespaceAST: public DeclarationAST +{ + DECLARE_AST_NODE(Namespace) + + std::size_t namespace_name; + LinkageBodyAST *linkage_body; +}; + +struct NamespaceAliasDefinitionAST: public DeclarationAST +{ + DECLARE_AST_NODE(NamespaceAliasDefinition) + + std::size_t namespace_name; + NameAST *alias_name; +}; + +struct NewDeclaratorAST: public AST +{ + DECLARE_AST_NODE(NewDeclarator) + + PtrOperatorAST *ptr_op; + NewDeclaratorAST *sub_declarator; + const ListNode<ExpressionAST*> *expressions; +}; + +struct NewExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(NewExpression) + + std::size_t scope_token; + std::size_t new_token; + ExpressionAST *expression; + TypeIdAST *type_id; + NewTypeIdAST *new_type_id; + NewInitializerAST *new_initializer; +}; + +struct NewInitializerAST: public AST +{ + DECLARE_AST_NODE(NewInitializer) + + ExpressionAST *expression; +}; + +struct NewTypeIdAST: public AST +{ + DECLARE_AST_NODE(NewTypeId) + + TypeSpecifierAST *type_specifier; + NewInitializerAST *new_initializer; + NewDeclaratorAST *new_declarator; +}; + +struct OperatorAST: public AST +{ + DECLARE_AST_NODE(Operator) + + std::size_t op; + std::size_t open; + std::size_t close; +}; + +struct OperatorFunctionIdAST: public AST +{ + DECLARE_AST_NODE(OperatorFunctionId) + + OperatorAST *op; + TypeSpecifierAST *type_specifier; + const ListNode<PtrOperatorAST*> *ptr_ops; +}; + +struct ParameterDeclarationAST: public AST +{ + DECLARE_AST_NODE(ParameterDeclaration) + + TypeSpecifierAST *type_specifier; + DeclaratorAST *declarator; + ExpressionAST *expression; +}; + +struct ParameterDeclarationClauseAST: public AST +{ + DECLARE_AST_NODE(ParameterDeclarationClause) + + const ListNode<ParameterDeclarationAST*> *parameter_declarations; + std::size_t ellipsis; +}; + +struct PostfixExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(PostfixExpression) + + TypeSpecifierAST *type_specifier; + ExpressionAST *expression; + const ListNode<ExpressionAST*> *sub_expressions; +}; + +struct PrimaryExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(PrimaryExpression) + + StringLiteralAST *literal; + std::size_t token; + StatementAST *expression_statement; + ExpressionAST *sub_expression; + NameAST *name; +}; + +struct PtrOperatorAST: public AST +{ + DECLARE_AST_NODE(PtrOperator) + + const ListNode<std::size_t> *cv; + std::size_t op; + PtrToMemberAST *mem_ptr; +}; + +struct PtrToMemberAST: public AST +{ + DECLARE_AST_NODE(PtrToMember) +}; + +struct ReturnStatementAST: public StatementAST +{ + DECLARE_AST_NODE(ReturnStatement) + + ExpressionAST *expression; +}; + +struct SimpleDeclarationAST: public DeclarationAST +{ + DECLARE_AST_NODE(SimpleDeclaration) + + const ListNode<std::size_t> *storage_specifiers; + const ListNode<std::size_t> *function_specifiers; + TypeSpecifierAST *type_specifier; + const ListNode<InitDeclaratorAST*> *init_declarators; + WinDeclSpecAST *win_decl_specifiers; +}; + +struct SimpleTypeSpecifierAST: public TypeSpecifierAST +{ + DECLARE_AST_NODE(SimpleTypeSpecifier) + + const ListNode<std::size_t> *integrals; + std::size_t type_of; + TypeIdAST *type_id; + ExpressionAST *expression; + NameAST *name; +}; + +struct SizeofExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(SizeofExpression) + + std::size_t sizeof_token; + TypeIdAST *type_id; + ExpressionAST *expression; +}; + +struct StringLiteralAST: public AST +{ + DECLARE_AST_NODE(StringLiteral) + + const ListNode<std::size_t> *literals; +}; + +struct SubscriptExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(SubscriptExpression) + + ExpressionAST *subscript; +}; + +struct SwitchStatementAST: public StatementAST +{ + DECLARE_AST_NODE(SwitchStatement) + + ConditionAST *condition; + StatementAST *statement; +}; + +struct TemplateArgumentAST: public AST +{ + DECLARE_AST_NODE(TemplateArgument) + + TypeIdAST *type_id; + ExpressionAST *expression; +}; + +struct TemplateDeclarationAST: public DeclarationAST +{ + DECLARE_AST_NODE(TemplateDeclaration) + + std::size_t exported; + const ListNode<TemplateParameterAST*> *template_parameters; + DeclarationAST* declaration; +}; + +struct TemplateParameterAST: public AST +{ + DECLARE_AST_NODE(TemplateParameter) + + TypeParameterAST *type_parameter; + ParameterDeclarationAST *parameter_declaration; +}; + +struct ThrowExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(ThrowExpression) + + std::size_t throw_token; + ExpressionAST *expression; +}; + +struct TranslationUnitAST: public AST +{ + DECLARE_AST_NODE(TranslationUnit) + + const ListNode<DeclarationAST*> *declarations; +}; + +struct TryBlockStatementAST: public StatementAST +{ + DECLARE_AST_NODE(TryBlockStatement) +}; + +struct TypeIdAST: public AST +{ + DECLARE_AST_NODE(TypeId) + + TypeSpecifierAST *type_specifier; + DeclaratorAST *declarator; +}; + +struct TypeIdentificationAST: public ExpressionAST +{ + DECLARE_AST_NODE(TypeIdentification) + + std::size_t typename_token; + NameAST *name; + ExpressionAST *expression; +}; + +struct TypeParameterAST: public AST +{ + DECLARE_AST_NODE(TypeParameter) + + std::size_t type; + NameAST *name; + TypeIdAST *type_id; + const ListNode<TemplateParameterAST*> *template_parameters; + NameAST *template_name; +}; + +struct TypedefAST: public DeclarationAST +{ + DECLARE_AST_NODE(Typedef) + + TypeSpecifierAST *type_specifier; + const ListNode<InitDeclaratorAST*> *init_declarators; +}; + +struct UnaryExpressionAST: public ExpressionAST +{ + DECLARE_AST_NODE(UnaryExpression) + + std::size_t op; + ExpressionAST *expression; +}; + +struct UnqualifiedNameAST: public AST +{ + DECLARE_AST_NODE(UnqualifiedName) + + std::size_t tilde; + std::size_t id; + OperatorFunctionIdAST *operator_id; + const ListNode<TemplateArgumentAST*> *template_arguments; +}; + +struct UsingAST: public DeclarationAST +{ + DECLARE_AST_NODE(Using) + + std::size_t type_name; + NameAST *name; +}; + +struct UsingDirectiveAST: public DeclarationAST +{ + DECLARE_AST_NODE(UsingDirective) + + NameAST *name; +}; + +struct WhileStatementAST: public StatementAST +{ + DECLARE_AST_NODE(WhileStatement) + + ConditionAST *condition; + StatementAST *statement; +}; + +struct WinDeclSpecAST: public AST +{ + DECLARE_AST_NODE(WinDeclSpec) + + std::size_t specifier; + std::size_t modifier; +}; + +struct QPropertyAST : public DeclarationAST +{ + DECLARE_AST_NODE(QPropertyAST) +}; + +struct QEnumsAST : public DeclarationAST +{ + DECLARE_AST_NODE(QEnumsAST) +}; + +template <class _Tp> +_Tp *CreateNode(pool *memory_pool) +{ + _Tp *node = reinterpret_cast<_Tp*>(memory_pool->allocate(sizeof(_Tp), strideof(_Tp))); + node->kind = _Tp::__node_kind; + return node; +} + +template <class _Tp> +_Tp ast_cast(AST *item) +{ + if (item && static_cast<_Tp>(0)->__node_kind == item->kind) + return static_cast<_Tp>(item); + + return 0; +} + +#endif // AST_H diff --git a/sources/shiboken2/ApiExtractor/parser/binder.cpp b/sources/shiboken2/ApiExtractor/parser/binder.cpp new file mode 100644 index 000000000..709f86c56 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/binder.cpp @@ -0,0 +1,866 @@ +/**************************************************************************** +** +** 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 "binder.h" +#include "lexer.h" +#include "control.h" +#include "symbol.h" +#include "codemodel_finder.h" +#include "class_compiler.h" +#include "compiler_utils.h" +#include "tokens.h" +#include "dumptree.h" + +#include <iostream> +#include <QDebug> + +Binder::Binder(CodeModel *__model, LocationManager &__location, Control *__control) + : _M_model(__model), + _M_location(__location), + _M_token_stream(&_M_location.token_stream), + _M_control(__control), + _M_current_function_type(CodeModel::Normal), + type_cc(this), + name_cc(this), + decl_cc(this) +{ + _M_qualified_types.insert(QLatin1String("char"), QString()); + _M_qualified_types.insert(QLatin1String("double"), QString()); + _M_qualified_types.insert(QLatin1String("float"), QString()); + _M_qualified_types.insert(QLatin1String("int"), QString()); + _M_qualified_types.insert(QLatin1String("long"), QString()); + _M_qualified_types.insert(QLatin1String("short"), QString()); + _M_qualified_types.insert(QLatin1String("void"), QString()); +} + +Binder::~Binder() +{ +} + +FileModelItem Binder::run(AST *node) +{ + FileModelItem old = _M_current_file; + _M_current_access = CodeModel::Public; + + _M_current_file.reset(new _FileModelItem(model())); + updateItemPosition(_M_current_file, node); + visit(node); + FileModelItem result = _M_current_file; + + _M_current_file = old; // restore + + return result; +} + +ScopeModelItem Binder::currentScope() +{ + if (_M_current_class) + return _M_current_class; + else if (_M_current_namespace) + return _M_current_namespace; + + return _M_current_file; +} + +TemplateParameterList Binder::changeTemplateParameters(TemplateParameterList templateParameters) +{ + TemplateParameterList old = _M_current_template_parameters; + _M_current_template_parameters = templateParameters; + return old; +} + +CodeModel::FunctionType Binder::changeCurrentFunctionType(CodeModel::FunctionType functionType) +{ + CodeModel::FunctionType old = _M_current_function_type; + _M_current_function_type = functionType; + return old; +} + +CodeModel::AccessPolicy Binder::changeCurrentAccess(CodeModel::AccessPolicy accessPolicy) +{ + CodeModel::AccessPolicy old = _M_current_access; + _M_current_access = accessPolicy; + return old; +} + +NamespaceModelItem Binder::changeCurrentNamespace(NamespaceModelItem item) +{ + NamespaceModelItem old = _M_current_namespace; + _M_current_namespace = item; + return old; +} + +ClassModelItem Binder::changeCurrentClass(ClassModelItem item) +{ + ClassModelItem old = _M_current_class; + _M_current_class = item; + return old; +} + +FunctionModelItem Binder::changeCurrentFunction(FunctionModelItem item) +{ + FunctionModelItem old = _M_current_function; + _M_current_function = item; + return old; +} + +int Binder::decode_token(std::size_t index) const +{ + return _M_token_stream->kind(index); +} + +CodeModel::AccessPolicy Binder::decode_access_policy(std::size_t index) const +{ + switch (decode_token(index)) { + case Token_class: + return CodeModel::Private; + + case Token_struct: + case Token_union: + return CodeModel::Public; + + default: + return CodeModel::Public; + } +} + +CodeModel::ClassType Binder::decode_class_type(std::size_t index) const +{ + switch (decode_token(index)) { + case Token_class: + return CodeModel::Class; + case Token_struct: + return CodeModel::Struct; + case Token_union: + return CodeModel::Union; + default: + std::cerr << "** WARNING unrecognized class type" << std::endl; + } + return CodeModel::Class; +} + +const NameSymbol *Binder::decode_symbol(std::size_t index) const +{ + return _M_token_stream->symbol(index); +} + +void Binder::visitAccessSpecifier(AccessSpecifierAST *node) +{ + const ListNode<std::size_t> *it = node->specs; + if (!it) + return; + + it = it->toFront(); + const ListNode<std::size_t> *end = it; + + do { + switch (decode_token(it->element)) { + default: + break; + + case Token_public: + changeCurrentAccess(CodeModel::Public); + changeCurrentFunctionType(CodeModel::Normal); + break; + case Token_protected: + changeCurrentAccess(CodeModel::Protected); + changeCurrentFunctionType(CodeModel::Normal); + break; + case Token_private: + changeCurrentAccess(CodeModel::Private); + changeCurrentFunctionType(CodeModel::Normal); + break; + case Token_signals: + changeCurrentAccess(CodeModel::Protected); + changeCurrentFunctionType(CodeModel::Signal); + break; + case Token_slots: + changeCurrentFunctionType(CodeModel::Slot); + break; + } + it = it->next; + } while (it != end); +} + +void Binder::visitSimpleDeclaration(SimpleDeclarationAST *node) +{ + visit(node->type_specifier); + + if (const ListNode<InitDeclaratorAST*> *it = node->init_declarators) { + it = it->toFront(); + const ListNode<InitDeclaratorAST*> *end = it; + do { + InitDeclaratorAST *init_declarator = it->element; + declare_symbol(node, init_declarator); + it = it->next; + } while (it != end); + } +} + +void Binder::declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator) +{ + DeclaratorAST *declarator = init_declarator->declarator; + + while (declarator && declarator->sub_declarator) + declarator = declarator->sub_declarator; + + NameAST *id = declarator->id; + if (!declarator->id) { + std::cerr << "** WARNING expected a declarator id" << std::endl; + return; + } + + CodeModelFinder finder(model(), this); + ScopeModelItem symbolScope = finder.resolveScope(id, currentScope()); + if (!symbolScope) { + name_cc.run(id); + std::cerr << "** WARNING scope not found for symbol:" + << qPrintable(name_cc.name()) << std::endl; + return; + } + + decl_cc.run(declarator); + + if (decl_cc.isFunction()) { + name_cc.run(id->unqualified_name); + + FunctionModelItem fun(new _FunctionModelItem(model(), name_cc.name())); + updateItemPosition(fun, node); + fun->setAccessPolicy(_M_current_access); + fun->setFunctionType(_M_current_function_type); + fun->setAbstract(init_declarator->initializer != 0); + fun->setConstant(declarator->fun_cv != 0); + fun->setTemplateParameters(_M_current_template_parameters); + applyStorageSpecifiers(node->storage_specifiers, fun); + applyFunctionSpecifiers(node->function_specifiers, fun); + + // build the type + TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier, + declarator, + this); + + fun->setType(qualifyType(typeInfo, symbolScope->qualifiedName())); + + + fun->setVariadics(decl_cc.isVariadics()); + + // ... and the signature + foreach (const DeclaratorCompiler::Parameter &p, decl_cc.parameters()) { + ArgumentModelItem arg(new _ArgumentModelItem(model(), p.name)); + arg->setType(qualifyType(p.type, _M_context)); + arg->setDefaultValue(p.defaultValue); + if (p.defaultValue) + arg->setDefaultValueExpression(p.defaultValueExpression); + fun->addArgument(arg); + } + + fun->setScope(symbolScope->qualifiedName()); + symbolScope->addFunction(fun); + } else { + VariableModelItem var(new _VariableModelItem(model())); + updateItemPosition(var, node); + var->setTemplateParameters(_M_current_template_parameters); + var->setAccessPolicy(_M_current_access); + name_cc.run(id->unqualified_name); + var->setName(name_cc.name()); + // Possible bug, because second parameter uses declarator instead of + // init_declarator->declarator like in DeclaratorCompiler::visitParameterDeclaration, + // but it doesn't seem to affect anything because the generator doesn't currently use + // variable declarations, only function declarations (because it cares about the API only, + // variable declarations are not exposed to the target language). + // See PYSIDE-455. + TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier, + declarator, + this); + if (declarator != init_declarator->declarator + && init_declarator->declarator->parameter_declaration_clause) { + typeInfo.setFunctionPointer(true); + decl_cc.run(init_declarator->declarator); + foreach (const DeclaratorCompiler::Parameter &p, decl_cc.parameters()) + typeInfo.addArgument(p.type); + } + + var->setType(qualifyType(typeInfo, _M_context)); + applyStorageSpecifiers(node->storage_specifiers, var); + + var->setScope(symbolScope->qualifiedName()); + symbolScope->addVariable(var); + } +} + +void Binder::visitFunctionDefinition(FunctionDefinitionAST *node) +{ + Q_ASSERT(node->init_declarator); + + ScopeModelItem scope = currentScope(); + + InitDeclaratorAST *init_declarator = node->init_declarator; + DeclaratorAST *declarator = init_declarator->declarator; + + // in the case of "void (func)()" or "void ((func))()" we need to + // skip to the inner most. This is in line with how the declarator + // node is generated in 'parser.cpp' + while (declarator && declarator->sub_declarator) + declarator = declarator->sub_declarator; + if (!declarator->id) { + std::cerr << "** WARNING temp hack for Qt 5.6.0: " + << "skipped a class that inherits from a private class" + << std::endl; + return; + } + Q_ASSERT(declarator->id); + + CodeModelFinder finder(model(), this); + + ScopeModelItem functionScope = finder.resolveScope(declarator->id, scope); + if (!functionScope) { + name_cc.run(declarator->id); + std::cerr << "** WARNING scope not found for function definition:" + << qPrintable(name_cc.name()) << std::endl + << "\tdefinition *ignored*" + << std::endl; + return; + } + + decl_cc.run(declarator); + + Q_ASSERT(!decl_cc.id().isEmpty()); + + FunctionModelItem + old = changeCurrentFunction(FunctionModelItem(new _FunctionModelItem(_M_model))); + _M_current_function->setScope(functionScope->qualifiedName()); + updateItemPosition(_M_current_function, node); + + Q_ASSERT(declarator->id->unqualified_name); + name_cc.run(declarator->id->unqualified_name); + QString unqualified_name = name_cc.name(); + + _M_current_function->setName(unqualified_name); + TypeInfo tmp_type = CompilerUtils::typeDescription(node->type_specifier, + declarator, this); + + _M_current_function->setType(qualifyType(tmp_type, _M_context)); + _M_current_function->setAccessPolicy(_M_current_access); + _M_current_function->setFunctionType(_M_current_function_type); + _M_current_function->setConstant(declarator->fun_cv); + _M_current_function->setTemplateParameters(_M_current_template_parameters); + + applyStorageSpecifiers(node->storage_specifiers, + _M_current_function); + applyFunctionSpecifiers(node->function_specifiers, + _M_current_function); + + _M_current_function->setVariadics(decl_cc.isVariadics()); + + foreach (const DeclaratorCompiler::Parameter &p, decl_cc.parameters()) { + ArgumentModelItem arg(new _ArgumentModelItem(model(), p.name)); + arg->setType(qualifyType(p.type, functionScope->qualifiedName())); + arg->setDefaultValue(p.defaultValue); + if (p.defaultValue) + arg->setDefaultValueExpression(p.defaultValueExpression); + _M_current_function->addArgument(arg); + } + + FunctionModelItem prototype = _M_current_function; + FunctionModelItem declared = functionScope->declaredFunction(prototype); + + // try to find a function declaration for this definition.. + if (!declared) { + functionScope->addFunction(prototype); + } else { + applyFunctionSpecifiers(node->function_specifiers, declared); + + // fix the function type and the access policy + _M_current_function->setAccessPolicy(declared->accessPolicy()); + _M_current_function->setFunctionType(declared->functionType()); + } + + changeCurrentFunction(old); +} + +void Binder::visitTemplateDeclaration(TemplateDeclarationAST *node) +{ + const ListNode<TemplateParameterAST*> *it = node->template_parameters; + if (!it) { + // QtScript: we want to visit the declaration still, so that + // e.g. QMetaTypeId<Foo> is added to the code model + visit(node->declaration); + return; + } + + TemplateParameterList savedTemplateParameters = changeTemplateParameters(TemplateParameterList()); + + it = it->toFront(); + const ListNode<TemplateParameterAST*> *end = it; + + TemplateParameterList templateParameters; + do { + TemplateParameterAST *parameter = it->element; + TypeParameterAST *type_parameter = parameter->type_parameter; + + NameAST *name; + if (!type_parameter) { + // A hacky hack to work around missing support for parameter declarations in + // templates. We just need the to get the name of the variable, since we + // aren't actually compiling these anyway. We are still not supporting much + // more, but we are refusing to fail for a few more declarations + if (!parameter->parameter_declaration || + !parameter->parameter_declaration->declarator || + !parameter->parameter_declaration->declarator->id) { + + /*std::cerr << "** WARNING template declaration not supported ``"; + Token const &tk = _M_token_stream->token ((int) node->start_token); + Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token); + + std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''" + << std::endl << std::endl;*/ + + changeTemplateParameters(savedTemplateParameters); + return; + + } + + name = parameter->parameter_declaration->declarator->id; + } else { + int tk = decode_token(type_parameter->type); + if (tk != Token_typename && tk != Token_class) { + /*std::cerr << "** WARNING template declaration not supported ``"; + Token const &tk = _M_token_stream->token ((int) node->start_token); + Token const &end_tk = _M_token_stream->token ((int) node->declaration->start_token); + + std::cerr << std::string (&tk.text[tk.position], (end_tk.position) - tk.position) << "''" + << std::endl << std::endl;*/ + + changeTemplateParameters(savedTemplateParameters); + return; + } + assert(tk == Token_typename || tk == Token_class); + + name = type_parameter->name; + } + + + name_cc.run(name); + const TemplateParameterModelItem p(new _TemplateParameterModelItem(model(), name_cc.name())); + _M_current_template_parameters.append(p); + it = it->next; + } while (it != end); + + visit(node->declaration); + + changeTemplateParameters(savedTemplateParameters); +} + +void Binder::visitTypedef(TypedefAST *node) +{ + const ListNode<InitDeclaratorAST*> *it = node->init_declarators; + if (!it) + return; + + it = it->toFront(); + const ListNode<InitDeclaratorAST*> *end = it; + + do { + InitDeclaratorAST *init_declarator = it->element; + it = it->next; + + Q_ASSERT(init_declarator->declarator); + + // the name + decl_cc.run(init_declarator->declarator); + QString alias_name = decl_cc.id(); + + if (alias_name.isEmpty()) { + std::cerr << "** WARNING anonymous typedef not supported! ``"; + Token const &tk = _M_token_stream->token((int) node->start_token); + Token const &end_tk = _M_token_stream->token((int) node->end_token); + + std::cerr << std::string(&tk.text[tk.position], end_tk.position - tk.position) << "''" + << std::endl << std::endl; + continue; + } + + // build the type + TypeInfo typeInfo = CompilerUtils::typeDescription(node->type_specifier, + init_declarator->declarator, + this); + DeclaratorAST *decl = init_declarator->declarator; + while (decl && decl->sub_declarator) + decl = decl->sub_declarator; + + if (decl != init_declarator->declarator + && init_declarator->declarator->parameter_declaration_clause) { + typeInfo.setFunctionPointer(true); + decl_cc.run(init_declarator->declarator); + foreach (const DeclaratorCompiler::Parameter &p, decl_cc.parameters()) + typeInfo.addArgument(p.type); + } + + ScopeModelItem scope = currentScope(); + DeclaratorAST *declarator = init_declarator->declarator; + CodeModelFinder finder(model(), this); + ScopeModelItem typedefScope = finder.resolveScope(declarator->id, scope); + + TypeDefModelItem typeDef(new _TypeDefModelItem(model())); + updateItemPosition(typeDef, node); + typeDef->setName(alias_name); + typeDef->setType(qualifyType(typeInfo, currentScope()->qualifiedName())); + typeDef->setScope(typedefScope->qualifiedName()); + _M_qualified_types[typeDef->qualifiedName().join(QLatin1Char('.'))] = QString(); + currentScope()->addTypeDef(typeDef); + } while (it != end); +} + +void Binder::visitNamespace(NamespaceAST *node) +{ + bool anonymous = (node->namespace_name == 0); + + ScopeModelItem scope = currentScope(); + + NamespaceModelItem old; + if (!anonymous) { + QString name = decode_symbol(node->namespace_name)->as_string(); + + QStringList qualified_name = scope->qualifiedName(); + qualified_name += name; + const CodeModelItem nsI = _M_model->findItem(qualified_name, _M_current_file); + NamespaceModelItem ns = qSharedPointerDynamicCast<_NamespaceModelItem>(nsI); + if (!ns) { + ns.reset(new _NamespaceModelItem(_M_model)); + updateItemPosition(ns, node); + ns->setName(name); + ns->setScope(scope->qualifiedName()); + } + old = changeCurrentNamespace(ns); + + _M_context.append(name); + } + + DefaultVisitor::visitNamespace(node); + + if (!anonymous) { + Q_ASSERT(scope->kind() == _CodeModelItem::Kind_Namespace + || scope->kind() == _CodeModelItem::Kind_File); + + _M_context.removeLast(); + + if (const NamespaceModelItem ns = qSharedPointerDynamicCast<_NamespaceModelItem>(scope)) + ns->addNamespace(_M_current_namespace); + + changeCurrentNamespace(old); + } +} + +void Binder::visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *node) +{ + name_cc.run(node->name); + if (name_cc.name().isEmpty()) + return; + + ScopeModelItem scope = currentScope(); + _M_qualified_types[(scope->qualifiedName() + name_cc.qualifiedName()).join(QLatin1Char('.'))] = QString(); +} + +void Binder::visitClassSpecifier(ClassSpecifierAST *node) +{ + ClassCompiler class_cc(this); + class_cc.run(node); + + if (class_cc.name().isEmpty()) { + // anonymous not supported + return; + } + + Q_ASSERT(node->name && node->name->unqualified_name); + + ScopeModelItem scope = currentScope(); + + ClassModelItem old = changeCurrentClass(ClassModelItem(new _ClassModelItem(_M_model))); + updateItemPosition(_M_current_class, node); + _M_current_class->setName(class_cc.name()); + + QStringList baseClasses = class_cc.baseClasses(); + TypeInfo info; + for (int i = 0; i < baseClasses.size(); ++i) { + info.setQualifiedName(baseClasses.at(i).split(QLatin1String("::"))); + baseClasses[i] = qualifyType(info, scope->qualifiedName()).qualifiedName().join(QLatin1String("::")); + } + + _M_current_class->setBaseClasses(baseClasses); + _M_current_class->setClassType(decode_class_type(node->class_key)); + _M_current_class->setTemplateParameters(_M_current_template_parameters); + + if (!_M_current_template_parameters.isEmpty()) { + QString name = _M_current_class->name(); + name += QLatin1Char('<'); + for (int i = 0; i < _M_current_template_parameters.size(); ++i) { + if (i > 0) + name += QLatin1Char(','); + + name += _M_current_template_parameters.at(i)->name(); + } + + name += QLatin1Char('>'); + _M_current_class->setName(name); + } + + CodeModel::AccessPolicy oldAccessPolicy = changeCurrentAccess(decode_access_policy(node->class_key)); + CodeModel::FunctionType oldFunctionType = changeCurrentFunctionType(CodeModel::Normal); + + _M_current_class->setScope(scope->qualifiedName()); + _M_qualified_types[_M_current_class->qualifiedName().join(QLatin1Char('.'))] = QString(); + + scope->addClass(_M_current_class); + + name_cc.run(node->name->unqualified_name); + _M_context.append(name_cc.name()); + visitNodes(this, node->member_specs); + _M_context.removeLast(); + + changeCurrentClass(old); + changeCurrentAccess(oldAccessPolicy); + changeCurrentFunctionType(oldFunctionType); +} + +void Binder::visitLinkageSpecification(LinkageSpecificationAST *node) +{ + DefaultVisitor::visitLinkageSpecification(node); +} + +void Binder::visitUsing(UsingAST *node) +{ + DefaultVisitor::visitUsing(node); +} + +void Binder::visitEnumSpecifier(EnumSpecifierAST *node) +{ + CodeModelFinder finder(model(), this); + ScopeModelItem scope = currentScope(); + ScopeModelItem enumScope = finder.resolveScope(node->name, scope); + + name_cc.run(node->name); + QString name = name_cc.name(); + + bool isAnonymous = name.isEmpty(); + if (isAnonymous) { + // anonymous enum + QString key = _M_context.join(QLatin1String("::")); + int current = ++_M_anonymous_enums[key]; + name += QLatin1String("enum_"); + name += QString::number(current); + } + + _M_current_enum.reset(new _EnumModelItem(model())); + _M_current_enum->setAccessPolicy(_M_current_access); + updateItemPosition(_M_current_enum, node); + _M_current_enum->setName(name); + _M_current_enum->setAnonymous(isAnonymous); + _M_current_enum->setScope(enumScope->qualifiedName()); + + _M_qualified_types[_M_current_enum->qualifiedName().join(QLatin1Char('.'))] = QString(); + + enumScope->addEnum(_M_current_enum); + + DefaultVisitor::visitEnumSpecifier(node); + + _M_current_enum.clear(); +} + +static QString strip_preprocessor_lines(const QString &name) +{ + QStringList lst = name.split(QLatin1Char('\n')); + QString s; + for (int i = 0; i < lst.size(); ++i) { + if (!lst.at(i).startsWith(QLatin1Char('#'))) + s += lst.at(i); + } + return s.trimmed(); +} + +void Binder::visitEnumerator(EnumeratorAST *node) +{ + Q_ASSERT(_M_current_enum); + EnumeratorModelItem e(new _EnumeratorModelItem(model())); + updateItemPosition(e, node); + e->setName(decode_symbol(node->id)->as_string()); + + if (ExpressionAST *expr = node->expression) { + const Token &start_token = _M_token_stream->token((int) expr->start_token); + const Token &end_token = _M_token_stream->token((int) expr->end_token); + const QString token = QString::fromUtf8(&start_token.text[start_token.position], + (int)(end_token.position - start_token.position)); + QString lines = strip_preprocessor_lines(token.trimmed()); + lines.remove(QLatin1Char(' ')); + e->setValue(lines); + } + + _M_current_enum->addEnumerator(e); +} + +void Binder::visitUsingDirective(UsingDirectiveAST *node) +{ + DefaultVisitor::visitUsingDirective(node); +} + +void Binder::visitQEnums(QEnumsAST *node) +{ + const Token &start = _M_token_stream->token((int) node->start_token); + const Token &end = _M_token_stream->token((int) node->end_token); + QStringList enum_list = QString::fromLatin1(start.text + start.position, + end.position - start.position).split(QLatin1Char(' ')); + + ScopeModelItem scope = currentScope(); + for (int i = 0; i < enum_list.size(); ++i) + scope->addEnumsDeclaration(enum_list.at(i)); +} + +void Binder::visitQProperty(QPropertyAST *node) +{ + const Token &start = _M_token_stream->token((int) node->start_token); + const Token &end = _M_token_stream->token((int) node->end_token); + QString property = QString::fromLatin1(start.text + start.position, + end.position - start.position); + _M_current_class->addPropertyDeclaration(property); +} + +void Binder::applyStorageSpecifiers(const ListNode<std::size_t> *it, MemberModelItem item) +{ + if (!it) + return; + + it = it->toFront(); + const ListNode<std::size_t> *end = it; + + do { + switch (decode_token(it->element)) { + default: + break; + + case Token_friend: + item->setFriend(true); + break; + case Token_auto: + item->setAuto(true); + break; + case Token_register: + item->setRegister(true); + break; + case Token_static: + item->setStatic(true); + break; + case Token_extern: + item->setExtern(true); + break; + case Token_mutable: + item->setMutable(true); + break; + } + it = it->next; + } while (it != end); +} + +void Binder::applyFunctionSpecifiers(const ListNode<std::size_t> *it, FunctionModelItem item) +{ + if (!it) + return; + + it = it->toFront(); + const ListNode<std::size_t> *end = it; + + do { + switch (decode_token(it->element)) { + default: + break; + + case Token_inline: + item->setInline(true); + break; + + case Token_virtual: + item->setVirtual(true); + break; + + case Token_explicit: + item->setExplicit(true); + break; + + case Token_Q_INVOKABLE: + item->setInvokable(true); + break; + } + it = it->next; + } while (it != end); +} + +TypeInfo Binder::qualifyType(const TypeInfo &type, const QStringList &context) const +{ + // ### Potentially improve to use string list in the name table to + if (!context.size()) { + // ### We can assume that this means global namespace for now... + return type; + } else if (_M_qualified_types.contains(type.qualifiedName().join(QLatin1Char('.')))) { + return type; + } else { + QStringList expanded = context; + expanded << type.qualifiedName(); + if (_M_qualified_types.contains(expanded.join(QLatin1Char('.')))) { + TypeInfo modified_type = type; + modified_type.setQualifiedName(expanded); + return modified_type; + } else { + CodeModelItem scope = model()->findItem(context, _M_current_file); + + if (ClassModelItem klass = qSharedPointerDynamicCast<_ClassModelItem>(scope)) { + foreach (const QString &base, klass->baseClasses()) { + QStringList ctx = context; + ctx.removeLast(); + ctx.append(base); + + TypeInfo qualified = qualifyType(type, ctx); + if (qualified != type) + return qualified; + } + } + + QStringList copy = context; + copy.removeLast(); + return qualifyType(type, copy); + } + } +} + +void Binder::updateItemPosition(CodeModelItem item, AST *node) +{ + QString filename; + int line, column; + + assert(node); + _M_location.positionAt(_M_token_stream->position(node->start_token), &line, &column, &filename); + item->setFileName(filename); +} diff --git a/sources/shiboken2/ApiExtractor/parser/binder.h b/sources/shiboken2/ApiExtractor/parser/binder.h new file mode 100644 index 000000000..cd8d93a95 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/binder.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** 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 BINDER_H +#define BINDER_H + +#include "default_visitor.h" +#include "codemodel.h" +#include "type_compiler.h" +#include "name_compiler.h" +#include "declarator_compiler.h" + +class TokenStream; +class LocationManager; +class Control; +struct NameSymbol; + +class Binder: protected DefaultVisitor +{ +public: + Binder(CodeModel *__model, LocationManager &__location, Control *__control = 0); + virtual ~Binder(); + + inline TokenStream *tokenStream() const + { + return _M_token_stream; + } + + inline CodeModel *model() const + { + return _M_model; + } + + ScopeModelItem currentScope(); + + FileModelItem run(AST *node); + +// utils + TypeInfo qualifyType(const TypeInfo &type, const QStringList &context) const; + +protected: + virtual void visitAccessSpecifier(AccessSpecifierAST *); + virtual void visitClassSpecifier(ClassSpecifierAST *); + virtual void visitEnumSpecifier(EnumSpecifierAST *); + virtual void visitEnumerator(EnumeratorAST *); + virtual void visitFunctionDefinition(FunctionDefinitionAST *); + virtual void visitLinkageSpecification(LinkageSpecificationAST *); + virtual void visitNamespace(NamespaceAST *); + virtual void visitSimpleDeclaration(SimpleDeclarationAST *); + virtual void visitTemplateDeclaration(TemplateDeclarationAST *); + virtual void visitTypedef(TypedefAST *); + virtual void visitUsing(UsingAST *); + virtual void visitUsingDirective(UsingDirectiveAST *); + virtual void visitQProperty(QPropertyAST *); + virtual void visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *); + virtual void visitQEnums(QEnumsAST *); + +private: + + int decode_token(std::size_t index) const; + const NameSymbol *decode_symbol(std::size_t index) const; + CodeModel::AccessPolicy decode_access_policy(std::size_t index) const; + CodeModel::ClassType decode_class_type(std::size_t index) const; + + CodeModel::FunctionType changeCurrentFunctionType(CodeModel::FunctionType functionType); + CodeModel::AccessPolicy changeCurrentAccess(CodeModel::AccessPolicy accessPolicy); + NamespaceModelItem changeCurrentNamespace(NamespaceModelItem item); + ClassModelItem changeCurrentClass(ClassModelItem item); + FunctionModelItem changeCurrentFunction(FunctionModelItem item); + TemplateParameterList changeTemplateParameters(TemplateParameterList templateParameters); + + void declare_symbol(SimpleDeclarationAST *node, InitDeclaratorAST *init_declarator); + + void applyStorageSpecifiers(const ListNode<std::size_t> *storage_specifiers, MemberModelItem item); + void applyFunctionSpecifiers(const ListNode<std::size_t> *it, FunctionModelItem item); + + void updateItemPosition(CodeModelItem item, AST *node); + +private: + CodeModel *_M_model; + LocationManager &_M_location; + TokenStream *_M_token_stream; + Control *_M_control; + + CodeModel::FunctionType _M_current_function_type; + CodeModel::AccessPolicy _M_current_access; + FileModelItem _M_current_file; + NamespaceModelItem _M_current_namespace; + ClassModelItem _M_current_class; + FunctionModelItem _M_current_function; + EnumModelItem _M_current_enum; + QStringList _M_context; + TemplateParameterList _M_current_template_parameters; // ### check me + QHash<QString, QString> _M_qualified_types; + QHash<QString, int> _M_anonymous_enums; + void dummy() { + _M_control=0; + } + +protected: + TypeCompiler type_cc; + NameCompiler name_cc; + DeclaratorCompiler decl_cc; +}; + +#endif // BINDER_H diff --git a/sources/shiboken2/ApiExtractor/parser/class_compiler.cpp b/sources/shiboken2/ApiExtractor/parser/class_compiler.cpp new file mode 100644 index 000000000..3387412ff --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/class_compiler.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 "class_compiler.h" +#include "lexer.h" +#include "binder.h" + +ClassCompiler::ClassCompiler(Binder *binder) + : _M_binder(binder), + _M_token_stream(binder->tokenStream()), + name_cc(_M_binder), + type_cc(_M_binder) +{ +} + +ClassCompiler::~ClassCompiler() +{ +} + +void ClassCompiler::run(ClassSpecifierAST *node) +{ + name_cc.run(node->name); + _M_name = name_cc.name(); + _M_base_classes.clear(); + + visit(node); +} + +void ClassCompiler::visitClassSpecifier(ClassSpecifierAST *node) +{ + visit(node->base_clause); +} + +void ClassCompiler::visitBaseSpecifier(BaseSpecifierAST *node) +{ + name_cc.run(node->name); + QString name = name_cc.name(); + + if (!name.isEmpty()) + _M_base_classes.append(name); +} + + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/class_compiler.h b/sources/shiboken2/ApiExtractor/parser/class_compiler.h new file mode 100644 index 000000000..09b727fe6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/class_compiler.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 CLASS_COMPILER_H +#define CLASS_COMPILER_H + +#include <QtCore/qglobal.h> +#include <QtCore/QStringList> + +#include <default_visitor.h> +#include <name_compiler.h> +#include <type_compiler.h> + +class TokenStream; +class Binder; + +class ClassCompiler: protected DefaultVisitor +{ +public: + ClassCompiler(Binder *binder); + virtual ~ClassCompiler(); + + inline QString name() const + { + return _M_name; + } + + inline QStringList baseClasses() const + { + return _M_base_classes; + } + + void run(ClassSpecifierAST *node); + +protected: + virtual void visitClassSpecifier(ClassSpecifierAST *node); + virtual void visitBaseSpecifier(BaseSpecifierAST *node); + +private: + Binder *_M_binder; + TokenStream *_M_token_stream; + QString _M_name; + QStringList _M_base_classes; + NameCompiler name_cc; + TypeCompiler type_cc; +}; + +#endif // CLASS_COMPILER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp new file mode 100644 index 000000000..a5024c4a3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.cpp @@ -0,0 +1,1199 @@ +/**************************************************************************** +** +** 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 QList<QSharedPointer<T> > &list, const QString &name) +{ + typedef typename QList<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(')'); + } + + foreach(QString elt, arrayElements()) { + tmp += QLatin1Char('['); + tmp += elt; + tmp += QLatin1Char(']'); + } + + return tmp; +} + +bool TypeInfo::operator==(const TypeInfo &other) +{ + 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) +{ + foreach (const FunctionModelItem &fun, 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; + foreach (const FunctionModelItem &func, m_functions) { + if (func->name() == name) + result.append(func); + } + return result; +} + +// --------------------------------------------------------------------------- +_NamespaceModelItem::~_NamespaceModelItem() +{ +} + +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..811cfec3e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/codemodel.h @@ -0,0 +1,691 @@ +/**************************************************************************** +** +** 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/QList> +#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; + } + + QList<TypeInfo> arguments() const + { + return m_arguments; + } + + void setArguments(const QList<TypeInfo> &arguments); + + void addArgument(const TypeInfo &arg) + { + m_arguments.append(arg); + } + + bool operator==(const TypeInfo &other); + + bool operator!=(const TypeInfo &other) + { + 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; + QList<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 Q_DECL_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 Q_DECL_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 { return m_namespaces.toSet(); } + + void addNamespace(NamespaceModelItem item); + + NamespaceModelItem findNamespace(const QString &name) const; + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const Q_DECL_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 Q_DECL_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 Q_DECL_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 Q_DECL_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 Q_DECL_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 Q_DECL_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 Q_DECL_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 Q_DECL_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_finder.cpp b/sources/shiboken2/ApiExtractor/parser/codemodel_finder.cpp new file mode 100644 index 000000000..57f8ae0cf --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/codemodel_finder.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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_finder.h" +#include "codemodel.h" +#include "binder.h" + +CodeModelFinder::CodeModelFinder(CodeModel *model, Binder *binder) + : _M_model(model), + _M_binder(binder), + _M_token_stream(binder->tokenStream()), + name_cc(_M_binder), + _M_resolve_policy(ResolveItem) +{ +} + +CodeModelFinder::~CodeModelFinder() +{ +} + +ScopeModelItem CodeModelFinder::resolveScope(NameAST *name, ScopeModelItem scope) +{ + Q_ASSERT(scope); + + ResolvePolicy saved_resolve_policy = _M_resolve_policy; + _M_resolve_policy = ResolveScope; + + ScopeModelItem old = changeCurrentScope(scope); + + visit(name); + ScopeModelItem result = _M_current_scope; + + changeCurrentScope(old); // restore + + _M_resolve_policy = saved_resolve_policy; + + return result; +} + +ScopeModelItem CodeModelFinder::changeCurrentScope(ScopeModelItem scope) +{ + ScopeModelItem old = _M_current_scope; + _M_current_scope = scope; + return old; +} + +void CodeModelFinder::visitName(NameAST *node) +{ + visitNodes(this, node->qualified_names); + + if (_M_resolve_policy == ResolveItem) + visit(node->unqualified_name); +} + +void CodeModelFinder::visitUnqualifiedName(UnqualifiedNameAST *node) +{ + if (!_M_current_scope) { + // nothing to do + return; + } + + name_cc.run(node); + QString id = name_cc.name(); + + if (ClassModelItem klass = _M_current_scope->findClass(id)) { + _M_current_scope = klass; + } else if (NamespaceModelItem parentNamespace = qSharedPointerDynamicCast<_NamespaceModelItem>(_M_current_scope)) { + NamespaceModelItem ns = parentNamespace->findNamespace(id); + _M_current_scope = ns; + } else if (FileModelItem file = qSharedPointerDynamicCast<_FileModelItem>(_M_current_scope)) { + NamespaceModelItem ns = file->findNamespace(id); + _M_current_scope = ns; + } +} + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/sources/shiboken2/ApiExtractor/parser/codemodel_finder.h b/sources/shiboken2/ApiExtractor/parser/codemodel_finder.h new file mode 100644 index 000000000..0217cbac6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/codemodel_finder.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** 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_FINDER_H +#define CODEMODEL_FINDER_H + +#include <default_visitor.h> +#include <codemodel_fwd.h> +#include <name_compiler.h> + +class TokenStream; +class Binder; + +class CodeModelFinder: protected DefaultVisitor +{ + enum ResolvePolicy { + ResolveScope, + ResolveItem + }; + +public: + CodeModelFinder(CodeModel *model, Binder *binder); + virtual ~CodeModelFinder(); + + ScopeModelItem resolveScope(NameAST *name, ScopeModelItem scope); + + inline CodeModel *model() const + { + return _M_model; + } + +protected: + virtual void visitName(NameAST *node); + virtual void visitUnqualifiedName(UnqualifiedNameAST *node); + + ScopeModelItem changeCurrentScope(ScopeModelItem scope); + +private: + CodeModel *_M_model; + Binder *_M_binder; + TokenStream *_M_token_stream; + NameCompiler name_cc; + + ScopeModelItem _M_current_scope; + ResolvePolicy _M_resolve_policy; +}; + +#endif // CODEMODEL_FINDER_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..676bda872 --- /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/QList> +#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 QList<ArgumentModelItem> ArgumentList; +typedef QList<ClassModelItem> ClassList; +typedef QList<CodeModelItem> ItemList; +typedef QList<EnumModelItem> EnumList; +typedef QList<EnumeratorModelItem> EnumeratorList; +typedef QList<FileModelItem> FileList; +typedef QList<FunctionModelItem> FunctionList; +typedef QList<NamespaceModelItem> NamespaceList; +typedef QList<ScopeModelItem> ScopeList; +typedef QList<TemplateParameterModelItem> TemplateParameterList; +typedef QList<TypeDefModelItem> TypeDefList; +typedef QList<VariableModelItem> VariableList; +typedef QList<MemberModelItem> MemberList; + +#endif // CODEMODEL_FWD_H diff --git a/sources/shiboken2/ApiExtractor/parser/compiler_utils.cpp b/sources/shiboken2/ApiExtractor/parser/compiler_utils.cpp new file mode 100644 index 000000000..95a9db6c3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/compiler_utils.cpp @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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 "compiler_utils.h" +#include "type_compiler.h" +#include "name_compiler.h" +#include "declarator_compiler.h" +#include "ast.h" +#include "binder.h" + +TypeInfo CompilerUtils::typeDescription(TypeSpecifierAST *type_specifier, DeclaratorAST *declarator, Binder *binder) +{ + TypeCompiler type_cc(binder); + DeclaratorCompiler decl_cc(binder); + + type_cc.run(type_specifier); + decl_cc.run(declarator); + + TypeInfo typeInfo; + typeInfo.setQualifiedName(type_cc.qualifiedName()); + typeInfo.setConstant(type_cc.isConstant()); + typeInfo.setVolatile(type_cc.isVolatile()); + typeInfo.setReferenceType(decl_cc.isReference() ? LValueReference : NoReference); + typeInfo.setIndirections(decl_cc.indirection()); + typeInfo.setArrayElements(decl_cc.arrayElements()); + + return typeInfo; +} diff --git a/sources/shiboken2/ApiExtractor/parser/compiler_utils.h b/sources/shiboken2/ApiExtractor/parser/compiler_utils.h new file mode 100644 index 000000000..849baf5aa --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/compiler_utils.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** 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 COMPILER_UTILS_H +#define COMPILER_UTILS_H + +#include <utility> + +#include "codemodel.h" + +struct TypeSpecifierAST; +struct DeclaratorAST; +class TokenStream; +class Binder; + +namespace CompilerUtils +{ + +TypeInfo typeDescription(TypeSpecifierAST *type_specifier, DeclaratorAST *declarator, Binder *binder); + +} // namespace CompilerUtils + +#endif // COMPILER_UTILS_H diff --git a/sources/shiboken2/ApiExtractor/parser/control.cpp b/sources/shiboken2/ApiExtractor/parser/control.cpp new file mode 100644 index 000000000..f86fa16bb --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/control.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** 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 "control.h" +#include "lexer.h" + +Control::Control() + : current_context(0), + _M_skipFunctionBody(false), + _M_lexer(0), + _M_parser(0) +{ + pushContext(); + + declareTypedef(findOrInsertName("__builtin_va_list", + strlen("__builtin_va_list")), 0); +} + +Control::~Control() +{ + popContext(); + + Q_ASSERT(current_context == 0); +} + +Lexer *Control::changeLexer(Lexer *lexer) +{ + Lexer *old = _M_lexer; + _M_lexer = lexer; + return old; +} + +Parser *Control::changeParser(Parser *parser) +{ + Parser *old = _M_parser; + _M_parser = parser; + return old; +} + +Type *Control::lookupType(const NameSymbol *name) const +{ + Q_ASSERT(current_context != 0); + + return current_context->resolve(name); +} + +void Control::declare(const NameSymbol *name, Type *type) +{ + //printf("*** Declare:"); + //printSymbol(name); + //putchar('\n'); + Q_ASSERT(current_context != 0); + + current_context->bind(name, type); +} + +void Control::pushContext() +{ + // printf("+Context\n"); + Context *new_context = new Context; + new_context->parent = current_context; + current_context = new_context; +} + +void Control::popContext() +{ + // printf("-Context\n"); + Q_ASSERT(current_context != 0); + + Context *old_context = current_context; + current_context = current_context->parent; + + delete old_context; +} + +void Control::declareTypedef(const NameSymbol *name, Declarator *d) +{ + // printf("declared typedef:"); + // printSymbol(name); + // printf("\n"); + stl_typedef_table.insert(name, d); +} + +bool Control::isTypedef(const NameSymbol *name) const +{ + // printf("is typedef:"); + // printSymbol(name); + // printf("= %d\n", (stl_typedef_table.find(name) != stl_typedef_table.end())); + + return stl_typedef_table.contains(name); +} + +QList<Control::ErrorMessage> Control::errorMessages() const +{ + return _M_error_messages; +} + +void Control::clearErrorMessages() +{ + _M_error_messages.clear(); +} + +void Control::reportError(const ErrorMessage &errmsg) +{ + _M_error_messages.append(errmsg); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/control.h b/sources/shiboken2/ApiExtractor/parser/control.h new file mode 100644 index 000000000..92635299e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/control.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** 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 CONTROL_H +#define CONTROL_H + +#include "symbol.h" +#include "smallobject.h" + +#include <QtCore/QHash> + +struct Declarator; +struct Type; +class Lexer; +class Parser; + +struct Context { + Context *parent; + + inline void bind(const NameSymbol *name, Type *type) { + symbol_table.insert(name, type); + } + + inline Type *resolve(const NameSymbol *name) const { + if (Type *type = symbol_table.value(name)) + return type; + else if (parent) + return parent->resolve(name); + + return 0; + } + + typedef QHash<const NameSymbol*, Type*> symbol_table_t; + + symbol_table_t symbol_table; +}; + +class Control +{ +public: + class ErrorMessage + { + public: + ErrorMessage(): + _M_line(0), + _M_column(0) {} + + inline int line() const { + return _M_line; + } + inline void setLine(int line) { + _M_line = line; + } + + inline int column() const { + return _M_column; + } + inline void setColumn(int column) { + _M_column = column; + } + + inline QString fileName() const { + return _M_fileName; + } + inline void setFileName(const QString &fileName) { + _M_fileName = fileName; + } + + inline QString message() const { + return _M_message; + } + inline void setMessage(const QString &message) { + _M_message = message; + } + + private: + int _M_line; + int _M_column; + QString _M_fileName; + QString _M_message; + }; + + Control(); + ~Control(); + + inline bool skipFunctionBody() const { + return _M_skipFunctionBody; + } + inline void setSkipFunctionBody(bool skip) { + _M_skipFunctionBody = skip; + } + + Lexer *changeLexer(Lexer *lexer); + Parser *changeParser(Parser *parser); + + Lexer *currentLexer() const { + return _M_lexer; + } + Parser *currentParser() const { + return _M_parser; + } + + Context *current_context; + + inline Context *currentContext() const { + return current_context; + } + + void pushContext(); + void popContext(); + + Type *lookupType(const NameSymbol *name) const; + void declare(const NameSymbol *name, Type *type); + + inline const NameSymbol *findOrInsertName(const char *data, size_t count) { + return name_table.findOrInsert(data, count); + } + + void declareTypedef(const NameSymbol *name, Declarator *d); + bool isTypedef(const NameSymbol *name) const; + + void reportError(const ErrorMessage &errmsg); + QList<ErrorMessage> errorMessages() const; + void clearErrorMessages(); + +private: + NameTable name_table; + QHash<const NameSymbol*, Declarator*> stl_typedef_table; + bool _M_skipFunctionBody; + Lexer *_M_lexer; + Parser *_M_parser; + + QList<ErrorMessage> _M_error_messages; +}; + +#endif // CONTROL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/declarator_compiler.cpp b/sources/shiboken2/ApiExtractor/parser/declarator_compiler.cpp new file mode 100644 index 000000000..e27ea5842 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/declarator_compiler.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** 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 "declarator_compiler.h" +#include "name_compiler.h" +#include "type_compiler.h" +#include "compiler_utils.h" +#include "lexer.h" +#include "binder.h" +#include "tokens.h" + +#include <qdebug.h> + +DeclaratorCompiler::DeclaratorCompiler(Binder *binder) + : _M_binder(binder), _M_token_stream(binder->tokenStream()) +{ +} + +void DeclaratorCompiler::run(DeclaratorAST *node) +{ + _M_id.clear(); + _M_parameters.clear(); + _M_array.clear(); + _M_function = false; + _M_reference = false; + _M_variadics = false; + _M_indirection = 0; + + if (node) { + NameCompiler name_cc(_M_binder); + + DeclaratorAST *decl = node; + while (decl && decl->sub_declarator) + decl = decl->sub_declarator; + + Q_ASSERT(decl != 0); + + name_cc.run(decl->id); + _M_id = name_cc.name(); + _M_function = (node->parameter_declaration_clause != 0); + if (node->parameter_declaration_clause && node->parameter_declaration_clause->ellipsis) + _M_variadics = true; + + visitNodes(this, node->ptr_ops); + visit(node->parameter_declaration_clause); + + if (const ListNode<ExpressionAST*> *it = node->array_dimensions) { + it->toFront(); + const ListNode<ExpressionAST*> *end = it; + + do { + QString elt; + if (ExpressionAST *expr = it->element) { + const Token &start_token = _M_token_stream->token((int) expr->start_token); + const Token &end_token = _M_token_stream->token((int) expr->end_token); + + elt += QString::fromUtf8(&start_token.text[start_token.position], + (int)(end_token.position - start_token.position)).trimmed(); + } + + _M_array.append(elt); + + it = it->next; + } while (it != end); + } + } +} + +void DeclaratorCompiler::visitPtrOperator(PtrOperatorAST *node) +{ + std::size_t op = _M_token_stream->kind(node->op); + + switch (op) { + case '&': + _M_reference = true; + break; + case '*': + ++_M_indirection; + break; + + default: + break; + } + + if (node->mem_ptr) { +#if defined(__GNUC__) +#warning "ptr to mem -- not implemented" +#endif + } +} + +void DeclaratorCompiler::visitParameterDeclaration(ParameterDeclarationAST *node) +{ + Parameter p; + DeclaratorCompiler decl_cc(_M_binder); + + // Find the innermost declarator, to extract the name / id of the declaration. + DeclaratorAST *declarator = node->declarator; + while (declarator && declarator->sub_declarator) + declarator = declarator->sub_declarator; + decl_cc.run(declarator); + p.name = decl_cc.id(); + + // Use the original declarator to extract the type. + p.type = CompilerUtils::typeDescription(node->type_specifier, node->declarator, _M_binder); + + // In case if the declarator is a function pointer, extract the arguments of the declarator + // parameter clause. This only works for top-declarator function pointers, it will fail to + // determine nested function pointers. + if (declarator != node->declarator + && node->declarator->parameter_declaration_clause) { + p.type.setFunctionPointer(true); + decl_cc.run(node->declarator); + foreach (const DeclaratorCompiler::Parameter &innerParam, decl_cc.parameters()) + p.type.addArgument(innerParam.type); + } + + if (node->expression != 0) { + const Token &start = _M_token_stream->token((int) node->expression->start_token); + const Token &end = _M_token_stream->token((int) node->expression->end_token); + int length = (int)(end.position - start.position); + + p.defaultValueExpression = QString(); + QString source = QString::fromUtf8(&start.text[start.position], length).trimmed(); + QStringList list = source.split(QLatin1Char('\n')); + + + for (int i = 0; i < list.size(); ++i) { + if (!list.at(i).startsWith(QLatin1Char('#'))) + p.defaultValueExpression += list.at(i).trimmed(); + } + + p.defaultValue = p.defaultValueExpression.size() > 0; + + } + + _M_parameters.append(p); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/declarator_compiler.h b/sources/shiboken2/ApiExtractor/parser/declarator_compiler.h new file mode 100644 index 000000000..f67bd4672 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/declarator_compiler.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** 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 DECLARATOR_COMPILER_H +#define DECLARATOR_COMPILER_H + +#include "default_visitor.h" +#include "codemodel.h" + +#include <QtCore/QString> +#include <QtCore/QList> + +class TokenStream; +class Binder; + +class DeclaratorCompiler: protected DefaultVisitor +{ +public: + struct Parameter { + TypeInfo type; + QString name; + QString defaultValueExpression; + bool defaultValue; + + Parameter(): defaultValue(false) {} + }; + +public: + DeclaratorCompiler(Binder *binder); + + void run(DeclaratorAST *node); + + inline QString id() const { + return _M_id; + } + inline QStringList arrayElements() const { + return _M_array; + } + inline bool isFunction() const { + return _M_function; + } + inline bool isVariadics() const { + return _M_variadics; + } + inline bool isReference() const { + return _M_reference; + } + inline int indirection() const { + return _M_indirection; + } + inline QList<Parameter> parameters() const { + return _M_parameters; + } + +protected: + virtual void visitPtrOperator(PtrOperatorAST *node); + virtual void visitParameterDeclaration(ParameterDeclarationAST *node); + +private: + Binder *_M_binder; + TokenStream *_M_token_stream; + + bool _M_function; + bool _M_reference; + bool _M_variadics; + int _M_indirection; + QString _M_id; + QStringList _M_array; + QList<Parameter> _M_parameters; +}; + +#endif // DECLARATOR_COMPILER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/default_visitor.cpp b/sources/shiboken2/ApiExtractor/parser/default_visitor.cpp new file mode 100644 index 000000000..e330abcbb --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/default_visitor.cpp @@ -0,0 +1,464 @@ +/**************************************************************************** +** +** 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 "default_visitor.h" + +void DefaultVisitor::visitAccessSpecifier(AccessSpecifierAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitAsmDefinition(AsmDefinitionAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitBaseClause(BaseClauseAST *node) +{ + visitNodes(this, node->base_specifiers); +} + +void DefaultVisitor::visitBaseSpecifier(BaseSpecifierAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitBinaryExpression(BinaryExpressionAST *node) +{ + visit(node->left_expression); + visit(node->right_expression); +} + +void DefaultVisitor::visitCastExpression(CastExpressionAST *node) +{ + visit(node->type_id); + visit(node->expression); +} + +void DefaultVisitor::visitClassMemberAccess(ClassMemberAccessAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitClassSpecifier(ClassSpecifierAST *node) +{ + visit(node->win_decl_specifiers); + visit(node->name); + visit(node->base_clause); + visitNodes(this, node->member_specs); +} + +void DefaultVisitor::visitCompoundStatement(CompoundStatementAST *node) +{ + visitNodes(this, node->statements); +} + +void DefaultVisitor::visitCondition(ConditionAST *node) +{ + visit(node->type_specifier); + visit(node->declarator); + visit(node->expression); +} + +void DefaultVisitor::visitConditionalExpression(ConditionalExpressionAST *node) +{ + visit(node->condition); + visit(node->left_expression); + visit(node->right_expression); +} + +void DefaultVisitor::visitCppCastExpression(CppCastExpressionAST *node) +{ + visit(node->type_id); + visit(node->expression); + visitNodes(this, node->sub_expressions); +} + +void DefaultVisitor::visitCtorInitializer(CtorInitializerAST *node) +{ + visitNodes(this, node->member_initializers); +} + +void DefaultVisitor::visitDeclarationStatement(DeclarationStatementAST *node) +{ + visit(node->declaration); +} + +void DefaultVisitor::visitDeclarator(DeclaratorAST *node) +{ + visit(node->sub_declarator); + visitNodes(this, node->ptr_ops); + visit(node->id); + visit(node->bit_expression); + visitNodes(this, node->array_dimensions); + visit(node->parameter_declaration_clause); + visit(node->exception_spec); +} + +void DefaultVisitor::visitDeleteExpression(DeleteExpressionAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitDoStatement(DoStatementAST *node) +{ + visit(node->statement); + visit(node->expression); +} + +void DefaultVisitor::visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitEnumSpecifier(EnumSpecifierAST *node) +{ + visit(node->name); + visitNodes(this, node->enumerators); +} + +void DefaultVisitor::visitEnumerator(EnumeratorAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitExceptionSpecification(ExceptionSpecificationAST *node) +{ + visitNodes(this, node->type_ids); +} + +void DefaultVisitor::visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *node) +{ + visit(node->expression); + visit(node->declaration); +} + +void DefaultVisitor::visitExpressionStatement(ExpressionStatementAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitForStatement(ForStatementAST *node) +{ + visit(node->init_statement); + visit(node->condition); + visit(node->expression); + visit(node->statement); +} + +void DefaultVisitor::visitFunctionCall(FunctionCallAST *node) +{ + visit(node->arguments); +} + +void DefaultVisitor::visitFunctionDefinition(FunctionDefinitionAST *node) +{ + visit(node->type_specifier); + visit(node->init_declarator); + visit(node->function_body); + visit(node->win_decl_specifiers); +} + +void DefaultVisitor::visitIfStatement(IfStatementAST *node) +{ + visit(node->condition); + visit(node->statement); + visit(node->else_statement); +} + +void DefaultVisitor::visitIncrDecrExpression(IncrDecrExpressionAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitInitDeclarator(InitDeclaratorAST *node) +{ + visit(node->declarator); + visit(node->initializer); +} + +void DefaultVisitor::visitInitializer(InitializerAST *node) +{ + visit(node->initializer_clause); + visit(node->expression); +} + +void DefaultVisitor::visitInitializerClause(InitializerClauseAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitLabeledStatement(LabeledStatementAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitLinkageBody(LinkageBodyAST *node) +{ + visitNodes(this, node->declarations); +} + +void DefaultVisitor::visitLinkageSpecification(LinkageSpecificationAST *node) +{ + visit(node->linkage_body); + visit(node->declaration); +} + +void DefaultVisitor::visitMemInitializer(MemInitializerAST *node) +{ + visit(node->initializer_id); + visit(node->expression); +} + +void DefaultVisitor::visitName(NameAST *node) +{ + visitNodes(this, node->qualified_names); + visit(node->unqualified_name); +} + +void DefaultVisitor::visitNamespace(NamespaceAST *node) +{ + visit(node->linkage_body); +} + +void DefaultVisitor::visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *node) +{ + visit(node->alias_name); +} + +void DefaultVisitor::visitNewDeclarator(NewDeclaratorAST *node) +{ + visit(node->ptr_op); + visit(node->sub_declarator); + visitNodes(this, node->expressions); +} + +void DefaultVisitor::visitNewExpression(NewExpressionAST *node) +{ + visit(node->expression); + visit(node->type_id); + visit(node->new_type_id); + visit(node->new_initializer); +} + +void DefaultVisitor::visitNewInitializer(NewInitializerAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitNewTypeId(NewTypeIdAST *node) +{ + visit(node->type_specifier); + visit(node->new_initializer); + visit(node->new_declarator); +} + +void DefaultVisitor::visitOperator(OperatorAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitOperatorFunctionId(OperatorFunctionIdAST *node) +{ + visit(node->op); + visit(node->type_specifier); + visitNodes(this, node->ptr_ops); +} + +void DefaultVisitor::visitParameterDeclaration(ParameterDeclarationAST *node) +{ + visit(node->type_specifier); + visit(node->declarator); + visit(node->expression); +} + +void DefaultVisitor::visitParameterDeclarationClause(ParameterDeclarationClauseAST *node) +{ + visitNodes(this, node->parameter_declarations); +} + +void DefaultVisitor::visitPostfixExpression(PostfixExpressionAST *node) +{ + visit(node->type_specifier); + visit(node->expression); + visitNodes(this, node->sub_expressions); +} + +void DefaultVisitor::visitPrimaryExpression(PrimaryExpressionAST *node) +{ + visit(node->literal); + visit(node->expression_statement); + visit(node->sub_expression); + visit(node->name); +} + +void DefaultVisitor::visitPtrOperator(PtrOperatorAST *node) +{ + visit(node->mem_ptr); +} + +void DefaultVisitor::visitPtrToMember(PtrToMemberAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitReturnStatement(ReturnStatementAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitSimpleDeclaration(SimpleDeclarationAST *node) +{ + visit(node->type_specifier); + visitNodes(this, node->init_declarators); + visit(node->win_decl_specifiers); +} + +void DefaultVisitor::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node) +{ + visit(node->name); + visit(node->type_id); + visit(node->expression); +} + +void DefaultVisitor::visitSizeofExpression(SizeofExpressionAST *node) +{ + visit(node->type_id); + visit(node->expression); +} + +void DefaultVisitor::visitStringLiteral(StringLiteralAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitSubscriptExpression(SubscriptExpressionAST *node) +{ + visit(node->subscript); +} + +void DefaultVisitor::visitSwitchStatement(SwitchStatementAST *node) +{ + visit(node->condition); + visit(node->statement); +} + +void DefaultVisitor::visitTemplateArgument(TemplateArgumentAST *node) +{ + visit(node->type_id); + visit(node->expression); +} + +void DefaultVisitor::visitTemplateDeclaration(TemplateDeclarationAST *node) +{ + visitNodes(this, node->template_parameters); + visit(node->declaration); +} + +void DefaultVisitor::visitTemplateParameter(TemplateParameterAST *node) +{ + visit(node->type_parameter); + visit(node->parameter_declaration); +} + +void DefaultVisitor::visitThrowExpression(ThrowExpressionAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitTranslationUnit(TranslationUnitAST *node) +{ + visitNodes(this, node->declarations); +} + +void DefaultVisitor::visitTryBlockStatement(TryBlockStatementAST *) +{ + // nothing to do +} + +void DefaultVisitor::visitTypeId(TypeIdAST *node) +{ + visit(node->type_specifier); + visit(node->declarator); +} + +void DefaultVisitor::visitTypeIdentification(TypeIdentificationAST *node) +{ + visit(node->name); + visit(node->expression); +} + +void DefaultVisitor::visitTypeParameter(TypeParameterAST *node) +{ + visit(node->name); + visit(node->type_id); + visitNodes(this, node->template_parameters); + visit(node->template_name); +} + +void DefaultVisitor::visitTypedef(TypedefAST *node) +{ + visit(node->type_specifier); + visitNodes(this, node->init_declarators); +} + +void DefaultVisitor::visitUnaryExpression(UnaryExpressionAST *node) +{ + visit(node->expression); +} + +void DefaultVisitor::visitUnqualifiedName(UnqualifiedNameAST *node) +{ + visit(node->operator_id); + visitNodes(this, node->template_arguments); +} + +void DefaultVisitor::visitUsing(UsingAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitUsingDirective(UsingDirectiveAST *node) +{ + visit(node->name); +} + +void DefaultVisitor::visitWhileStatement(WhileStatementAST *node) +{ + visit(node->condition); + visit(node->statement); +} + +void DefaultVisitor::visitWinDeclSpec(WinDeclSpecAST *) +{ + // nothing to do +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/default_visitor.h b/sources/shiboken2/ApiExtractor/parser/default_visitor.h new file mode 100644 index 000000000..1eef8cc85 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/default_visitor.h @@ -0,0 +1,123 @@ +/**************************************************************************** +** +** 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 DEFAULT_VISITOR_H +#define DEFAULT_VISITOR_H + +#include "visitor.h" + +class DefaultVisitor: public Visitor +{ +public: + DefaultVisitor() {} + +protected: + virtual void visitAccessSpecifier(AccessSpecifierAST *); + virtual void visitAsmDefinition(AsmDefinitionAST *); + virtual void visitBaseClause(BaseClauseAST *); + virtual void visitBaseSpecifier(BaseSpecifierAST *); + virtual void visitBinaryExpression(BinaryExpressionAST *); + virtual void visitCastExpression(CastExpressionAST *); + virtual void visitClassMemberAccess(ClassMemberAccessAST *); + virtual void visitClassSpecifier(ClassSpecifierAST *); + virtual void visitCompoundStatement(CompoundStatementAST *); + virtual void visitCondition(ConditionAST *); + virtual void visitConditionalExpression(ConditionalExpressionAST *); + virtual void visitCppCastExpression(CppCastExpressionAST *); + virtual void visitCtorInitializer(CtorInitializerAST *); + virtual void visitDeclarationStatement(DeclarationStatementAST *); + virtual void visitDeclarator(DeclaratorAST *); + virtual void visitDeleteExpression(DeleteExpressionAST *); + virtual void visitDoStatement(DoStatementAST *); + virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *); + virtual void visitEnumSpecifier(EnumSpecifierAST *); + virtual void visitEnumerator(EnumeratorAST *); + virtual void visitExceptionSpecification(ExceptionSpecificationAST *); + virtual void visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *); + virtual void visitExpressionStatement(ExpressionStatementAST *); + virtual void visitForStatement(ForStatementAST *); + virtual void visitFunctionCall(FunctionCallAST *); + virtual void visitFunctionDefinition(FunctionDefinitionAST *); + virtual void visitIfStatement(IfStatementAST *); + virtual void visitIncrDecrExpression(IncrDecrExpressionAST *); + virtual void visitInitDeclarator(InitDeclaratorAST *); + virtual void visitInitializer(InitializerAST *); + virtual void visitInitializerClause(InitializerClauseAST *); + virtual void visitLabeledStatement(LabeledStatementAST *); + virtual void visitLinkageBody(LinkageBodyAST *); + virtual void visitLinkageSpecification(LinkageSpecificationAST *); + virtual void visitMemInitializer(MemInitializerAST *); + virtual void visitName(NameAST *); + virtual void visitNamespace(NamespaceAST *); + virtual void visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *); + virtual void visitNewDeclarator(NewDeclaratorAST *); + virtual void visitNewExpression(NewExpressionAST *); + virtual void visitNewInitializer(NewInitializerAST *); + virtual void visitNewTypeId(NewTypeIdAST *); + virtual void visitOperator(OperatorAST *); + virtual void visitOperatorFunctionId(OperatorFunctionIdAST *); + virtual void visitParameterDeclaration(ParameterDeclarationAST *); + virtual void visitParameterDeclarationClause(ParameterDeclarationClauseAST *); + virtual void visitPostfixExpression(PostfixExpressionAST *); + virtual void visitPrimaryExpression(PrimaryExpressionAST *); + virtual void visitPtrOperator(PtrOperatorAST *); + virtual void visitPtrToMember(PtrToMemberAST *); + virtual void visitReturnStatement(ReturnStatementAST *); + virtual void visitSimpleDeclaration(SimpleDeclarationAST *); + virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *); + virtual void visitSizeofExpression(SizeofExpressionAST *); + virtual void visitStringLiteral(StringLiteralAST *); + virtual void visitSubscriptExpression(SubscriptExpressionAST *); + virtual void visitSwitchStatement(SwitchStatementAST *); + virtual void visitTemplateArgument(TemplateArgumentAST *); + virtual void visitTemplateDeclaration(TemplateDeclarationAST *); + virtual void visitTemplateParameter(TemplateParameterAST *); + virtual void visitThrowExpression(ThrowExpressionAST *); + virtual void visitTranslationUnit(TranslationUnitAST *); + virtual void visitTryBlockStatement(TryBlockStatementAST *); + virtual void visitTypeId(TypeIdAST *); + virtual void visitTypeIdentification(TypeIdentificationAST *); + virtual void visitTypeParameter(TypeParameterAST *); + virtual void visitTypedef(TypedefAST *); + virtual void visitUnaryExpression(UnaryExpressionAST *); + virtual void visitUnqualifiedName(UnqualifiedNameAST *); + virtual void visitUsing(UsingAST *); + virtual void visitUsingDirective(UsingDirectiveAST *); + virtual void visitWhileStatement(WhileStatementAST *); + virtual void visitWinDeclSpec(WinDeclSpecAST *); + +private: + typedef void (Visitor::*visitor_fun_ptr)(AST *); + static visitor_fun_ptr _S_table[]; +}; + +#endif // VISITOR_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/dumptree.cpp b/sources/shiboken2/ApiExtractor/parser/dumptree.cpp new file mode 100644 index 000000000..0a7444c14 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/dumptree.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** 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 "dumptree.h" + +#include <QtCore/QString> +#include <QtCore/qdebug.h> + +static char const * const names[] = { + 0, + "AccessSpecifier", + "AsmDefinition", + "BaseClause", + "BaseSpecifier", + "BinaryExpression", + "CastExpression", + "ClassMemberAccess", + "ClassSpecifier", + "CompoundStatement", + "Condition", + "ConditionalExpression", + "CppCastExpression", + "CtorInitializer", + "DeclarationStatement", + "Declarator", + "DeleteExpression", + "DoStatement", + "ElaboratedTypeSpecifier", + "EnumSpecifier", + "Enumerator", + "ExceptionSpecification", + "ExpressionOrDeclarationStatement", + "ExpressionStatement", + "ForStatement", + "FunctionCall", + "FunctionDefinition", + "IfStatement", + "IncrDecrExpression", + "InitDeclarator", + "Initializer", + "InitializerClause", + "LabeledStatement", + "LinkageBody", + "LinkageSpecification", + "MemInitializer", + "Name", + "Namespace", + "NamespaceAliasDefinition", + "NewDeclarator", + "NewExpression", + "NewInitializer", + "NewTypeId", + "Operator", + "OperatorFunctionId", + "ParameterDeclaration", + "ParameterDeclarationClause", + "PostfixExpression", + "PrimaryExpression", + "PtrOperator", + "PtrToMember", + "ReturnStatement", + "SimpleDeclaration", + "SimpleTypeSpecifier", + "SizeofExpression", + "StringLiteral", + "SubscriptExpression", + "SwitchStatement", + "TemplateArgument", + "TemplateDeclaration", + "TemplateParameter", + "ThrowExpression", + "TranslationUnit", + "TryBlockStatement", + "TypeId", + "TypeIdentification", + "TypeParameter", + "Typedef", + "UnaryExpression", + "UnqualifiedName", + "Using", + "UsingDirective", + "WhileStatement", + "WinDeclSpec" +}; + +DumpTree::DumpTree() +{ +} + +void DumpTree::visit(AST *node) +{ + static int indent = 0; + + + if (node) + qDebug() << QByteArray(indent * 2, ' ').constData() << names[node->kind] + << '[' << node->start_token << ", " << node->end_token << ']'; + + ++indent; + DefaultVisitor::visit(node); + --indent; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/dumptree.h b/sources/shiboken2/ApiExtractor/parser/dumptree.h new file mode 100644 index 000000000..5d91c6ef1 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/dumptree.h @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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 DUMPTREE_H +#define DUMPTREE_H + +#include "default_visitor.h" + +class DumpTree: protected DefaultVisitor +{ +public: + DumpTree(); + + void dump(AST *node) { + visit(node); + } + +protected: + virtual void visit(AST *node); +}; + +#endif // DUMPTREE_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/lexer.cpp b/sources/shiboken2/ApiExtractor/parser/lexer.cpp new file mode 100644 index 000000000..3fcf3b561 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/lexer.cpp @@ -0,0 +1,1726 @@ +/**************************************************************************** +** +** 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 "lexer.h" +#include "tokens.h" +#include "control.h" + +#include <cctype> +#include <iostream> + +scan_fun_ptr Lexer::s_scan_keyword_table[] = { + &Lexer::scanKeyword0, &Lexer::scanKeyword0, + &Lexer::scanKeyword2, &Lexer::scanKeyword3, + &Lexer::scanKeyword4, &Lexer::scanKeyword5, + &Lexer::scanKeyword6, &Lexer::scanKeyword7, + &Lexer::scanKeyword8, &Lexer::scanKeyword9, + &Lexer::scanKeyword10, &Lexer::scanKeyword11, + &Lexer::scanKeyword12, &Lexer::scanKeyword13, + &Lexer::scanKeyword14, &Lexer::scanKeyword0, + &Lexer::scanKeyword16 +}; + +void LocationManager::extract_line(int offset, int *line, QString *filename) const +{ + *line = 0; + if (token_stream.size() < 1) + return; + + const unsigned char *begin_buffer = reinterpret_cast<const unsigned char *>(token_stream[0].text); + const unsigned char *cursor = begin_buffer + offset; + + ++cursor; // skip '#' + if (std::isspace(*cursor) && std::isdigit(*(cursor + 1))) { + ++cursor; + char buffer[1024], *cp = buffer; + do { + *cp++ = *cursor++; + } while (std::isdigit(*cursor)); + *cp = '\0'; + int l = strtol(buffer, 0, 0); + + Q_ASSERT(std::isspace(*cursor)); + ++cursor; + + Q_ASSERT(*cursor == '"'); + ++cursor; + + cp = buffer; + while (*cursor && *cursor != '"') { + *cp++ = *cursor++; + } + *cp = '\0'; + Q_ASSERT(*cursor == '"'); + ++cursor; + + *filename = QLatin1String(buffer); + *line = l; + // printf("filename: %s line: %d\n", buffer, line); + } +} + +void LocationManager::positionAt(std::size_t offset, int *line, int *column, + QString *filename) const +{ + int ppline = 0; + int ppcolumn = 0; + line_table.positionAt(offset, &ppline, &ppcolumn); + + int base_line = 0; + extract_line((int) line_table[ppline-1], &base_line, filename); + + int line2 = 0; + int column2 = 0; + location_table.positionAt((int) line_table[ppline-1], &line2, &column2); + + location_table.positionAt(offset, line, column); + *line = base_line + *line - line2 - 1; +} + +scan_fun_ptr Lexer::s_scan_table[256]; +bool Lexer::s_initialized = false; + +void Lexer::tokenize(const char *contents, std::size_t size) +{ + if (!s_initialized) + initialize_scan_table(); + + token_stream.resize(1024); + token_stream[0].kind = Token_EOF; + token_stream[0].text = contents; + + index = 1; + + cursor = (const unsigned char *) contents; + begin_buffer = (const unsigned char *) contents; + end_buffer = cursor + size; + + location_table.resize(1024); + location_table[0] = 0; + location_table.current_line = 1; + + line_table.resize(1024); + line_table[0] = 0; + line_table.current_line = 1; + + do { + if (index == token_stream.size()) + token_stream.resize(token_stream.size() * 2); + + Token *current_token = &token_stream[(int) index]; + current_token->text = reinterpret_cast<const char*>(begin_buffer); + current_token->position = cursor - begin_buffer; + (this->*s_scan_table[*cursor])(); + current_token->size = cursor - begin_buffer - current_token->position; + } while (cursor < end_buffer); + + if (index == token_stream.size()) + token_stream.resize(token_stream.size() * 2); + + Q_ASSERT(index < token_stream.size()); + token_stream[(int) index].position = cursor - begin_buffer; + token_stream[(int) index].kind = Token_EOF; +} + +void Lexer::reportError(const QString& msg) +{ + int line = 0; + int column = 0; + QString fileName; + + std::size_t tok = token_stream.cursor(); + _M_location.positionAt(token_stream.position(tok), + &line, &column, &fileName); + + Control::ErrorMessage errmsg; + errmsg.setLine(line + 1); + errmsg.setColumn(column); + errmsg.setFileName(fileName); + errmsg.setMessage(QLatin1String("** LEXER ERROR ") + msg); + control->reportError(errmsg); +} + +void Lexer::initialize_scan_table() +{ + s_initialized = true; + + for (int i = 0; i < 256; ++i) { + if (isspace(i)) + s_scan_table[i] = &Lexer::scan_white_spaces; + else if (isalpha(i) || i == '_') + s_scan_table[i] = &Lexer::scan_identifier_or_keyword; + else if (isdigit(i)) + s_scan_table[i] = &Lexer::scan_int_constant; + else + s_scan_table[i] = &Lexer::scan_invalid_input; + } + + s_scan_table[int('L')] = &Lexer::scan_identifier_or_literal; + s_scan_table[int('\n')] = &Lexer::scan_newline; + s_scan_table[int('#')] = &Lexer::scan_preprocessor; + + s_scan_table[int('\'')] = &Lexer::scan_char_constant; + s_scan_table[int('"')] = &Lexer::scan_string_constant; + + s_scan_table[int('.')] = &Lexer::scan_int_constant; + + s_scan_table[int('!')] = &Lexer::scan_not; + s_scan_table[int('%')] = &Lexer::scan_remainder; + s_scan_table[int('&')] = &Lexer::scan_and; + s_scan_table[int('(')] = &Lexer::scan_left_paren; + s_scan_table[int(')')] = &Lexer::scan_right_paren; + s_scan_table[int('*')] = &Lexer::scan_star; + s_scan_table[int('+')] = &Lexer::scan_plus; + s_scan_table[int(',')] = &Lexer::scan_comma; + s_scan_table[int('-')] = &Lexer::scan_minus; + s_scan_table[int('/')] = &Lexer::scan_divide; + s_scan_table[int(':')] = &Lexer::scan_colon; + s_scan_table[int(';')] = &Lexer::scan_semicolon; + s_scan_table[int('<')] = &Lexer::scan_less; + s_scan_table[int('=')] = &Lexer::scan_equal; + s_scan_table[int('>')] = &Lexer::scan_greater; + s_scan_table[int('?')] = &Lexer::scan_question; + s_scan_table[int('[')] = &Lexer::scan_left_bracket; + s_scan_table[int(']')] = &Lexer::scan_right_bracket; + s_scan_table[int('^')] = &Lexer::scan_xor; + s_scan_table[int('{')] = &Lexer::scan_left_brace; + s_scan_table[int('|')] = &Lexer::scan_or; + s_scan_table[int('}')] = &Lexer::scan_right_brace; + s_scan_table[int('~')] = &Lexer::scan_tilde; + + s_scan_table[0] = &Lexer::scan_EOF; +} + +void Lexer::scan_preprocessor() +{ + if (line_table.current_line == line_table.size()) + line_table.resize(line_table.current_line * 2); + + line_table[(int) line_table.current_line++] = (cursor - begin_buffer); + + while (*cursor && *cursor != '\n') + ++cursor; + + if (*cursor != '\n') + reportError(QLatin1String("expected newline")); +} + +void Lexer::scan_char_constant() +{ + const unsigned char *begin = cursor; + + ++cursor; + while (*cursor && *cursor != '\'') { + if (*cursor == '\n') + reportError(QLatin1String("did not expect newline")); + + if (*cursor == '\\') + ++cursor; + ++cursor; + } + + if (*cursor != '\'') + reportError(QLatin1String("expected \'")); + + ++cursor; + + token_stream[(int) index].extra.symbol = + control->findOrInsertName((const char*) begin, cursor - begin); + + token_stream[(int) index++].kind = Token_char_literal; +} + +void Lexer::scan_string_constant() +{ + const unsigned char *begin = cursor; + + ++cursor; + while (*cursor && *cursor != '"') { + if (*cursor == '\n') + reportError(QLatin1String("did not expect newline")); + + if (*cursor == '\\') + ++cursor; + ++cursor; + } + + if (*cursor != '"') + reportError(QLatin1String("expected \"")); + + ++cursor; + + token_stream[(int) index].extra.symbol = + control->findOrInsertName((const char*) begin, cursor - begin); + + token_stream[(int) index++].kind = Token_string_literal; +} + +void Lexer::scan_newline() +{ + if (location_table.current_line == location_table.size()) + location_table.resize(location_table.current_line * 2); + + location_table[(int) location_table.current_line++] = (cursor - begin_buffer); + ++cursor; +} + +void Lexer::scan_white_spaces() +{ + while (isspace(*cursor)) { + if (*cursor == '\n') + scan_newline(); + else + ++cursor; + } +} + +void Lexer::scan_identifier_or_literal() +{ + switch (*(cursor + 1)) { + case '\'': + ++cursor; + scan_char_constant(); + break; + + case '\"': + ++cursor; + scan_string_constant(); + break; + + default: + scan_identifier_or_keyword(); + break; + } +} + +void Lexer::scan_identifier_or_keyword() +{ + const unsigned char *skip = cursor; + while (isalnum(*skip) || *skip == '_') + ++skip; + + int n = skip - cursor; + Token *current_token = &token_stream[(int) index]; + (this->*s_scan_keyword_table[n < 17 ? n : 0])(); + + if (current_token->kind == Token_identifier) { + current_token->extra.symbol = + control->findOrInsertName((const char*) cursor, n); + } + + cursor = skip; +} + +void Lexer::scan_int_constant() +{ + if (*cursor == '.' && !std::isdigit(*(cursor + 1))) { + scan_dot(); + return; + } + + const unsigned char *begin = cursor; + + while (isalnum(*cursor) || *cursor == '.') + ++cursor; + + token_stream[(int) index].extra.symbol = + control->findOrInsertName((const char*) begin, cursor - begin); + + token_stream[(int) index++].kind = Token_number_literal; +} + +void Lexer::scan_not() +{ + /* + '!' ::= not + '!=' ::= not_equal + */ + + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_not_eq; + } else { + token_stream[(int) index++].kind = '!'; + } +} + +void Lexer::scan_remainder() +{ + /* + '%' ::= remainder + '%=' ::= remainder_equal + */ + + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = '%'; + } +} + +void Lexer::scan_and() +{ + /* + '&&' ::= and_and + '&' ::= and + '&=' ::= and_equal + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else if (*cursor == '&') { + ++cursor; + token_stream[(int) index++].kind = Token_and; + } else { + token_stream[(int) index++].kind = '&'; + } +} + +void Lexer::scan_left_paren() +{ + ++cursor; + token_stream[(int) index++].kind = '('; +} + +void Lexer::scan_right_paren() +{ + ++cursor; + token_stream[(int) index++].kind = ')'; +} + +void Lexer::scan_star() +{ + /* + '*' ::= star + '*=' ::= star_equal + */ + + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = '*'; + } +} + +void Lexer::scan_plus() +{ + /* + '+' ::= plus + '++' ::= incr + '+=' ::= plus_equal + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else if (*cursor == '+') { + ++cursor; + token_stream[(int) index++].kind = Token_incr; + } else { + token_stream[(int) index++].kind = '+'; + } +} + +void Lexer::scan_comma() +{ + ++cursor; + token_stream[(int) index++].kind = ','; +} + +void Lexer::scan_minus() +{ + /* + '-' ::= minus + '--' ::= decr + '-=' ::= minus_equal + '->' ::= left_arrow + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else if (*cursor == '-') { + ++cursor; + token_stream[(int) index++].kind = Token_decr; + } else if (*cursor == '>') { + ++cursor; + token_stream[(int) index++].kind = Token_arrow; + if (*cursor == '*') { + ++cursor; + token_stream[(int) index++].kind = Token_ptrmem; + } + } else { + token_stream[(int) index++].kind = '-'; + } +} + +void Lexer::scan_dot() +{ + /* + '.' ::= dot + '...' ::= ellipsis + */ + + ++cursor; + if (*cursor == '.' && *(cursor + 1) == '.') { + cursor += 2; + token_stream[(int) index++].kind = Token_ellipsis; + } else if (*cursor == '.' && *(cursor + 1) == '*') { + cursor += 2; + token_stream[(int) index++].kind = Token_ptrmem; + } else + token_stream[(int) index++].kind = '.'; +} + +void Lexer::scan_divide() +{ + /* + '/' ::= divide + '/=' ::= divide_equal + */ + + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = '/'; + } +} + +void Lexer::scan_colon() +{ + ++cursor; + if (*cursor == ':') { + ++cursor; + token_stream[(int) index++].kind = Token_scope; + } else { + token_stream[(int) index++].kind = ':'; + } +} + +void Lexer::scan_semicolon() +{ + ++cursor; + token_stream[(int) index++].kind = ';'; +} + +void Lexer::scan_less() +{ + /* + '<' ::= less + '<<' ::= left_shift + '<<=' ::= left_shift_equal + '<=' ::= less_equal + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_leq; + } else if (*cursor == '<') { + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = Token_shift; + } + } else { + token_stream[(int) index++].kind = '<'; + } +} + +void Lexer::scan_equal() +{ + /* + '=' ::= equal + '==' ::= equal_equal + */ + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_eq; + } else { + token_stream[(int) index++].kind = '='; + } +} + +void Lexer::scan_greater() +{ + /* + '>' ::= greater + '>=' ::= greater_equal + '>>' ::= right_shift + '>>=' ::= right_shift_equal + */ + + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_geq; + } else if (*cursor == '>') { + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = Token_shift; + } + } else { + token_stream[(int) index++].kind = '>'; + } +} + +void Lexer::scan_question() +{ + ++cursor; + token_stream[(int) index++].kind = '?'; +} + +void Lexer::scan_left_bracket() +{ + ++cursor; + token_stream[(int) index++].kind = '['; +} + +void Lexer::scan_right_bracket() +{ + ++cursor; + token_stream[(int) index++].kind = ']'; +} + +void Lexer::scan_xor() +{ + /* + '^' ::= xor + '^=' ::= xor_equal + */ + ++cursor; + + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else { + token_stream[(int) index++].kind = '^'; + } +} + +void Lexer::scan_left_brace() +{ + ++cursor; + token_stream[(int) index++].kind = '{'; +} + +void Lexer::scan_or() +{ + /* + '|' ::= or + '|=' ::= or_equal + '||' ::= or_or + */ + ++cursor; + if (*cursor == '=') { + ++cursor; + token_stream[(int) index++].kind = Token_assign; + } else if (*cursor == '|') { + ++cursor; + token_stream[(int) index++].kind = Token_or; + } else { + token_stream[(int) index++].kind = '|'; + } +} + +void Lexer::scan_right_brace() +{ + ++cursor; + token_stream[(int) index++].kind = '}'; +} + +void Lexer::scan_tilde() +{ + ++cursor; + token_stream[(int) index++].kind = '~'; +} + +void Lexer::scan_EOF() +{ + ++cursor; + token_stream[(int) index++].kind = Token_EOF; +} + +void Lexer::scan_invalid_input() +{ + QString errmsg(QLatin1String("invalid input: %1")); + reportError(errmsg); + ++cursor; +} + +void LocationTable::positionAt(std::size_t offset, int max_line, + int *line, int *column) const +{ + if (!(line && column && max_line != 0)) + return; + + int first = 0; + int len = max_line; + int half; + int middle; + + while (len > 0) { + half = len >> 1; + middle = first; + + middle += half; + + if (lines[middle] < offset) { + first = middle; + ++first; + len = len - half - 1; + } else + len = half; + } + + *line = std::max(first, 1); + *column = (int)(offset - lines[*line - 1] - 1); + + if (*column < 0) { + *column = 0; + } +} + +void Lexer::scanKeyword0() +{ + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword2() +{ + switch (*cursor) { + case 'i': + if (*(cursor + 1) == 'f') { + token_stream[(int) index++].kind = Token_if; + return; + } + break; + + case 'd': + if (*(cursor + 1) == 'o') { + token_stream[(int) index++].kind = Token_do; + return; + } + break; + + case 'o': + if (*(cursor + 1) == 'r') { + token_stream[(int) index++].kind = Token_or; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword3() +{ + switch (*cursor) { + case 'a': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'd') { + token_stream[(int) index++].kind = Token_and; + return; + } + if (*(cursor + 1) == 's' && + *(cursor + 2) == 'm') { + token_stream[(int) index++].kind = Token_asm; + return; + } + break; + + case 'f': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'r') { + token_stream[(int) index++].kind = Token_for; + return; + } + break; + + case 'i': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 't') { + token_stream[(int) index++].kind = Token_int; + return; + } + break; + + case 'n': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'w') { + token_stream[(int) index++].kind = Token_new; + return; + } + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 't') { + token_stream[(int) index++].kind = Token_not; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'y') { + token_stream[(int) index++].kind = Token_try; + return; + } + break; + + case 'x': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'r') { + token_stream[(int) index++].kind = Token_xor; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword4() +{ + switch (*cursor) { + case 'a': + if (*(cursor + 1) == 'u' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'o') { + token_stream[(int) index++].kind = Token_auto; + return; + } + break; + + case 'c': + if (*(cursor + 1) == 'a' && + *(cursor + 2) == 's' && + *(cursor + 3) == 'e') { + token_stream[(int) index++].kind = Token_case; + return; + } + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 'r') { + token_stream[(int) index++].kind = Token_char; + return; + } + break; + + case 'b': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 'l') { + token_stream[(int) index++].kind = Token_bool; + return; + } + break; + + case 'e': + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 's' && + *(cursor + 3) == 'e') { + token_stream[(int) index++].kind = Token_else; + return; + } + if (*(cursor + 1) == 'm' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 't') { + token_stream[(int) index++].kind = Token_emit; + return; + } + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'u' && + *(cursor + 3) == 'm') { + token_stream[(int) index++].kind = Token_enum; + return; + } + break; + + case 'g': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'o') { + token_stream[(int) index++].kind = Token_goto; + return; + } + break; + + case 'l': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 'g') { + token_stream[(int) index++].kind = Token_long; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 's') { + token_stream[(int) index++].kind = Token_this; + return; + } + break; + + case 'v': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'd') { + token_stream[(int) index++].kind = Token_void; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword5() +{ + switch (*cursor) { + case 'c': + if (*(cursor + 1) == 'a' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'h') { + token_stream[(int) index++].kind = Token_catch; + return; + } + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 's' && + *(cursor + 4) == 's') { + token_stream[(int) index++].kind = Token_class; + return; + } + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'm' && + *(cursor + 3) == 'p' && + *(cursor + 4) == 'l') { + token_stream[(int) index++].kind = Token_compl; + return; + } + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 's' && + *(cursor + 4) == 't') { + token_stream[(int) index++].kind = Token_const; + return; + } + break; + + case 'b': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'r') { + token_stream[(int) index++].kind = Token_bitor; + return; + } + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'e' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'k') { + token_stream[(int) index++].kind = Token_break; + return; + } + break; + + case 'f': + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 't') { + token_stream[(int) index++].kind = Token_float; + return; + } + break; + + case 'o': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == '_' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'q') { + token_stream[(int) index++].kind = Token_or_eq; + return; + } + break; + + case 's': + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 'r' && + *(cursor + 4) == 't') { + token_stream[(int) index++].kind = Token_short; + return; + } + if (*(cursor + 1) == 'l' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 't' && + *(cursor + 4) == 's') { + token_stream[(int) index++].kind = Token_slots; + return; + } + break; + + case 'u': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'n') { + token_stream[(int) index++].kind = Token_union; + return; + } + if (*(cursor + 1) == 's' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'g') { + token_stream[(int) index++].kind = Token_using; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'r' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'w') { + token_stream[(int) index++].kind = Token_throw; + return; + } + break; + + case 'w': + if (*(cursor + 1) == 'h' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'e') { + token_stream[(int) index++].kind = Token_while; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword6() +{ + switch (*cursor) { + case 'a': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'd' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') { + token_stream[(int) index++].kind = Token_and_eq; + return; + } + break; + + case 'b': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'd') { + token_stream[(int) index++].kind = Token_bitand; + return; + } + break; + + case 'e': + if (*(cursor + 1) == 'x' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'o' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 't') { + token_stream[(int) index++].kind = Token_export; + return; + } + if (*(cursor + 1) == 'x' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 'n') { + token_stream[(int) index++].kind = Token_extern; + return; + } + break; + + case 'd': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'l' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'e') { + token_stream[(int) index++].kind = Token_delete; + return; + } + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'u' && + *(cursor + 3) == 'b' && + *(cursor + 4) == 'l' && + *(cursor + 5) == 'e') { + token_stream[(int) index++].kind = Token_double; + return; + } + break; + + case 'f': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'd') { + token_stream[(int) index++].kind = Token_friend; + return; + } + break; + + case 'i': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 'l' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'e') { + token_stream[(int) index++].kind = Token_inline; + return; + } + break; + + case 'K': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'D' && + *(cursor + 3) == 'C' && + *(cursor + 4) == 'O' && + *(cursor + 5) == 'P') { + token_stream[(int) index++].kind = Token_K_DCOP; + return; + } + break; + + case 'n': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 't' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') { + token_stream[(int) index++].kind = Token_not_eq; + return; + } + break; + + case 'p': + if (*(cursor + 1) == 'u' && + *(cursor + 2) == 'b' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c') { + token_stream[(int) index++].kind = Token_public; + return; + } + break; + + case 's': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 'g' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'd') { + token_stream[(int) index++].kind = Token_signed; + return; + } + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 'z' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'f') { + token_stream[(int) index++].kind = Token_sizeof; + return; + } + if (*(cursor + 1) == 't' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c') { + token_stream[(int) index++].kind = Token_static; + return; + } + if (*(cursor + 1) == 't' && + *(cursor + 2) == 'r' && + *(cursor + 3) == 'u' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 't') { + token_stream[(int) index++].kind = Token_struct; + return; + } + if (*(cursor + 1) == 'w' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 'h') { + token_stream[(int) index++].kind = Token_switch; + return; + } + break; + + case 'r': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'u' && + *(cursor + 4) == 'r' && + *(cursor + 5) == 'n') { + token_stream[(int) index++].kind = Token_return; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'y' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'd') { + token_stream[(int) index++].kind = Token_typeid; + return; + } + break; + + case 'x': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'r' && + *(cursor + 3) == '_' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'q') { + token_stream[(int) index++].kind = Token_xor_eq; + return; + } + break; + + case 'k': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'd' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'p') { + token_stream[(int) index++].kind = Token_k_dcop; + return; + } + break; + + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'E' && + *(cursor + 3) == 'N' && + *(cursor + 4) == 'U' && + *(cursor + 5) == 'M') { // Qt5.5 + token_stream[(int) index++].kind = Token_Q_ENUM; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword7() +{ + switch (*cursor) { + case 'd': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'f' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'u' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 't') { + token_stream[(int) index++].kind = Token_default; + return; + } + break; + + case 'm': + if (*(cursor + 1) == 'u' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'b' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 'e') { + token_stream[(int) index++].kind = Token_mutable; + return; + } + break; + + case 'p': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'v' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'e') { + token_stream[(int) index++].kind = Token_private; + return; + } + break; + case 's': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 'g' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 'l' && + *(cursor + 6) == 's') { + token_stream[(int) index++].kind = Token_signals; + return; + } + break; + case 't': + if (*(cursor + 1) == 'y' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'd' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'f') { + token_stream[(int) index++].kind = Token_typedef; + return; + } + break; + + case 'v': + if (*(cursor + 1) == 'i' && + *(cursor + 2) == 'r' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'u' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 'l') { + token_stream[(int) index++].kind = Token_virtual; + return; + } + break; + + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'E' && + *(cursor + 3) == 'N' && + *(cursor + 4) == 'U' && + *(cursor + 5) == 'M' && + *(cursor + 6) == 'S') { + token_stream[(int) index++].kind = Token_Q_ENUMS; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword8() +{ + switch (*cursor) { + case '_': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 't' && + *(cursor + 3) == 'y' && + *(cursor + 4) == 'p' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'o' && + *(cursor + 7) == 'f') { + token_stream[(int) index++].kind = Token___typeof; + return; + } + break; + + case 'c': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'n' && + *(cursor + 6) == 'u' && + *(cursor + 7) == 'e') { + token_stream[(int) index++].kind = Token_continue; + return; + } + break; + + case 'e': + if (*(cursor + 1) == 'x' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'l' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c' && + *(cursor + 6) == 'i' && + *(cursor + 7) == 't') { + token_stream[(int) index++].kind = Token_explicit; + return; + } + break; + + case 'n': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'e' && + *(cursor + 3) == 'x' && + *(cursor + 4) == 'c' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'p' && + *(cursor + 7) == 't') { + token_stream[(int) index++].kind = Token_noexcept; + return; + } + break; + + case 'o': + if (*(cursor + 1) == 'p' && + *(cursor + 2) == 'e' && + *(cursor + 3) == 'r' && + *(cursor + 4) == 'a' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'o' && + *(cursor + 7) == 'r') { + token_stream[(int) index++].kind = Token_operator; + return; + } + break; + + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'O' && + *(cursor + 3) == 'B' && + *(cursor + 4) == 'J' && + *(cursor + 5) == 'E' && + *(cursor + 6) == 'C' && + *(cursor + 7) == 'T') { + token_stream[(int) index++].kind = Token_Q_OBJECT; + return; + } + break; + + case 'r': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'g' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 's' && + *(cursor + 5) == 't' && + *(cursor + 6) == 'e' && + *(cursor + 7) == 'r') { + token_stream[(int) index++].kind = Token_register; + return; + } + break; + + case 'u': + if (*(cursor + 1) == 'n' && + *(cursor + 2) == 's' && + *(cursor + 3) == 'i' && + *(cursor + 4) == 'g' && + *(cursor + 5) == 'n' && + *(cursor + 6) == 'e' && + *(cursor + 7) == 'd') { + token_stream[(int) index++].kind = Token_unsigned; + return; + } + break; + + case 't': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'm' && + *(cursor + 3) == 'p' && + *(cursor + 4) == 'l' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 't' && + *(cursor + 7) == 'e') { + token_stream[(int) index++].kind = Token_template; + return; + } + if (*(cursor + 1) == 'y' && + *(cursor + 2) == 'p' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 'n' && + *(cursor + 5) == 'a' && + *(cursor + 6) == 'm' && + *(cursor + 7) == 'e') { + token_stream[(int) index++].kind = Token_typename; + return; + } + break; + + case 'v': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'l' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'i' && + *(cursor + 6) == 'l' && + *(cursor + 7) == 'e') { + token_stream[(int) index++].kind = Token_volatile; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword9() +{ + switch (*cursor) { + case 'p': + if (*(cursor + 1) == 'r' && + *(cursor + 2) == 'o' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'e' && + *(cursor + 5) == 'c' && + *(cursor + 6) == 't' && + *(cursor + 7) == 'e' && + *(cursor + 8) == 'd') { + token_stream[(int) index++].kind = Token_protected; + return; + } + break; + + case 'n': + if (*(cursor + 1) == 'a' && + *(cursor + 2) == 'm' && + *(cursor + 3) == 'e' && + *(cursor + 4) == 's' && + *(cursor + 5) == 'p' && + *(cursor + 6) == 'a' && + *(cursor + 7) == 'c' && + *(cursor + 8) == 'e') { + token_stream[(int) index++].kind = Token_namespace; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword10() +{ + switch (*cursor) { + case 'c': + if (*(cursor + 1) == 'o' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 's' && + *(cursor + 4) == 't' && + *(cursor + 5) == '_' && + *(cursor + 6) == 'c' && + *(cursor + 7) == 'a' && + *(cursor + 8) == 's' && + *(cursor + 9) == 't') { + token_stream[(int) index++].kind = Token_const_cast; + return; + } + break; + + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'P' && + *(cursor + 3) == 'R' && + *(cursor + 4) == 'O' && + *(cursor + 5) == 'P' && + *(cursor + 6) == 'E' && + *(cursor + 7) == 'R' && + *(cursor + 8) == 'T' && + *(cursor + 9) == 'Y') { + token_stream[(int) index++].kind = Token_Q_PROPERTY; + return; + } + + break; + } + + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword11() +{ + switch (*cursor) { + case 'Q': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'I' && + *(cursor + 3) == 'N' && + *(cursor + 4) == 'V' && + *(cursor + 5) == 'O' && + *(cursor + 6) == 'K' && + *(cursor + 7) == 'A' && + *(cursor + 8) == 'B' && + *(cursor + 9) == 'L' && + *(cursor + 10) == 'E') { + token_stream[(int) index++].kind = Token_Q_INVOKABLE; + return; + } + break; + + case 's': + if (*(cursor + 1) == 't' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 'i' && + *(cursor + 5) == 'c' && + *(cursor + 6) == '_' && + *(cursor + 7) == 'c' && + *(cursor + 8) == 'a' && + *(cursor + 9) == 's' && + *(cursor + 10) == 't') { + token_stream[(int) index++].kind = Token_static_cast; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword12() +{ + switch (*cursor) { + case 'd': + if (*(cursor + 1) == 'y' && + *(cursor + 2) == 'n' && + *(cursor + 3) == 'a' && + *(cursor + 4) == 'm' && + *(cursor + 5) == 'i' && + *(cursor + 6) == 'c' && + *(cursor + 7) == '_' && + *(cursor + 8) == 'c' && + *(cursor + 9) == 'a' && + *(cursor + 10) == 's' && + *(cursor + 11) == 't') { + token_stream[(int) index++].kind = Token_dynamic_cast; + return; + } + break; + + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword13() +{ + switch (*cursor) { + case '_': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'a' && + *(cursor + 3) == 't' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'r' && + *(cursor + 6) == 'i' && + *(cursor + 7) == 'b' && + *(cursor + 8) == 'u' && + *(cursor + 9) == 't' && + *(cursor + 10) == 'e' && + *(cursor + 11) == '_' && + *(cursor + 12) == '_') { + token_stream[(int) index++].kind = Token___attribute__; + return; + } + break; + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword14() +{ + switch (*cursor) { + case 'k': + if (*(cursor + 1) == '_' && + *(cursor + 2) == 'd' && + *(cursor + 3) == 'c' && + *(cursor + 4) == 'o' && + *(cursor + 5) == 'p' && + *(cursor + 6) == '_' && + *(cursor + 7) == 's' && + *(cursor + 8) == 'i' && + *(cursor + 9) == 'g' && + *(cursor + 10) == 'n' && + *(cursor + 11) == 'a' && + *(cursor + 12) == 'l' && + *(cursor + 13) == 's') { + token_stream[(int) index++].kind = Token_k_dcop_signals; + return; + } + break; + } + token_stream[(int) index++].kind = Token_identifier; +} + +void Lexer::scanKeyword16() +{ + switch (*cursor) { + case 'r': + if (*(cursor + 1) == 'e' && + *(cursor + 2) == 'i' && + *(cursor + 3) == 'n' && + *(cursor + 4) == 't' && + *(cursor + 5) == 'e' && + *(cursor + 6) == 'r' && + *(cursor + 7) == 'p' && + *(cursor + 8) == 'r' && + *(cursor + 9) == 'e' && + *(cursor + 10) == 't' && + *(cursor + 11) == '_' && + *(cursor + 12) == 'c' && + *(cursor + 13) == 'a' && + *(cursor + 14) == 's' && + *(cursor + 15) == 't') { + token_stream[(int) index++].kind = Token_reinterpret_cast; + return; + } + break; + } + + token_stream[(int) index++].kind = Token_identifier; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/lexer.h b/sources/shiboken2/ApiExtractor/parser/lexer.h new file mode 100644 index 000000000..7144355e4 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/lexer.h @@ -0,0 +1,295 @@ +/**************************************************************************** +** +** 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 LEXER_H +#define LEXER_H + +#include "symbol.h" + +#include <QtCore/QString> +#include <cstdlib> +#include <cassert> + +struct NameSymbol; +class Lexer; +class Control; + +typedef void (Lexer::*scan_fun_ptr)(); + +class Token +{ +public: + int kind; + std::size_t position; + std::size_t size; + char const *text; + + union { + const NameSymbol *symbol; + std::size_t right_brace; + } extra; +}; + +class LocationTable +{ +private: + LocationTable(const LocationTable &source); + void operator = (const LocationTable &source); + +public: + inline LocationTable(std::size_t size = 1024) + : lines(0), + line_count(0), + current_line(0) { + resize(size); + } + + inline ~LocationTable() { + free(lines); + } + + inline std::size_t size() const { + return line_count; + } + + void resize(std::size_t size) { + Q_ASSERT(size > 0); + lines = (std::size_t*) ::realloc(lines, sizeof(std::size_t) * size); + line_count = size; + } + + void positionAt(std::size_t offset, int *line, int *column) const { + positionAt(offset, (int) current_line, line, column); + } + + void positionAt(std::size_t offset, int max_line, int *line, int *column) const; + + inline std::size_t &operator[](int index) { + return lines[index]; + } + +private: + std::size_t *lines; + std::size_t line_count; + std::size_t current_line; + + friend class Lexer; +}; + +class TokenStream +{ +private: + TokenStream(const TokenStream &); + void operator = (const TokenStream &); + +public: + inline TokenStream(std::size_t size = 1024) + : tokens(0), + index(0), + token_count(0) { + resize(size); + } + + inline ~TokenStream() { + ::free(tokens); + } + + inline std::size_t size() const { + return token_count; + } + + inline std::size_t cursor() const { + return index; + } + + inline void rewind(int i) { + index = i; + } + + void resize(std::size_t size) { + Q_ASSERT(size > 0); + tokens = (Token*) ::realloc(tokens, sizeof(Token) * size); + token_count = size; + } + + inline std::size_t nextToken() { + return index++; + } + + inline int lookAhead(std::size_t i = 0) const { + return tokens[index + i].kind; + } + + inline int kind(std::size_t i) const { + return tokens[i].kind; + } + + inline std::size_t position(std::size_t i) const { + return tokens[i].position; + } + + inline const NameSymbol *symbol(std::size_t i) const { + return tokens[i].extra.symbol; + } + + inline std::size_t matchingBrace(std::size_t i) const { + return tokens[i].extra.right_brace; + } + + inline Token &operator[](int index) { + return tokens[index]; + } + + inline const Token &token(int index) const { + return tokens[index]; + } + +private: + Token *tokens; + std::size_t index; + std::size_t token_count; + +private: + friend class Lexer; +}; + +class LocationManager +{ + LocationManager(LocationManager const &__other); + void operator = (LocationManager const &__other); + +public: + LocationManager(TokenStream &__token_stream, + LocationTable &__location_table, + LocationTable &__line_table): + token_stream(__token_stream), + location_table(__location_table), + line_table(__line_table) {} + + void positionAt(std::size_t offset, int *line, int *column, + QString *filename) const; + + void extract_line(int offset, int *line, QString *filename) const; + + TokenStream &token_stream; + LocationTable &location_table; + LocationTable &line_table; +}; + +class Lexer +{ +public: + Lexer(LocationManager &__location, Control *__control): + _M_location(__location), + token_stream(_M_location.token_stream), + location_table(_M_location.location_table), + line_table(_M_location.line_table), + control(__control) {} + + void tokenize(const char *contents, std::size_t size); + + LocationManager &_M_location; + TokenStream &token_stream; + LocationTable &location_table; + LocationTable &line_table; + +private: + void reportError(const QString& msg); + + void initialize_scan_table(); + void scan_newline(); + void scan_white_spaces(); + void scan_identifier_or_keyword(); + void scan_identifier_or_literal(); + void scan_int_constant(); + void scan_char_constant(); + void scan_string_constant(); + void scan_invalid_input(); + void scan_preprocessor(); + + // keywords + void scanKeyword0(); + void scanKeyword2(); + void scanKeyword3(); + void scanKeyword4(); + void scanKeyword5(); + void scanKeyword6(); + void scanKeyword7(); + void scanKeyword8(); + void scanKeyword9(); + void scanKeyword10(); + void scanKeyword11(); + void scanKeyword12(); + void scanKeyword13(); + void scanKeyword14(); + void scanKeyword16(); + + // operators + void scan_not(); + void scan_remainder(); + void scan_and(); + void scan_left_paren(); + void scan_right_paren(); + void scan_star(); + void scan_plus(); + void scan_comma(); + void scan_minus(); + void scan_dot(); + void scan_divide(); + void scan_colon(); + void scan_semicolon(); + void scan_less(); + void scan_equal(); + void scan_greater(); + void scan_question(); + void scan_left_bracket(); + void scan_right_bracket(); + void scan_xor(); + void scan_left_brace(); + void scan_or(); + void scan_right_brace(); + void scan_tilde(); + void scan_EOF(); + +private: + Control *control; + const unsigned char *cursor; + const unsigned char *begin_buffer; + const unsigned char *end_buffer; + std::size_t index; + + static scan_fun_ptr s_scan_table[]; + static scan_fun_ptr s_scan_keyword_table[]; + static bool s_initialized; +}; + +#endif // LEXER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/list.cpp b/sources/shiboken2/ApiExtractor/parser/list.cpp new file mode 100644 index 000000000..2d2a78700 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/list.cpp @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** 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 "list.h" + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/list.h b/sources/shiboken2/ApiExtractor/parser/list.h new file mode 100644 index 000000000..764fafffd --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/list.h @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** 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 FASTLIST_H +#define FASTLIST_H + +#include "smallobject.h" + +template <typename Tp> +struct ListNode { + Tp element; + int index; + mutable const ListNode<Tp> *next; + + static ListNode *create(const Tp &element, pool *p) { + ListNode<Tp> *node = new(p->allocate(sizeof(ListNode), strideof(ListNode))) ListNode(); + node->element = element; + node->index = 0; + node->next = node; + + return node; + } + + static ListNode *create(const ListNode *n1, const Tp &element, pool *p) { + ListNode<Tp> *n2 = ListNode::create(element, p); + + n2->index = n1->index + 1; + n2->next = n1->next; + n1->next = n2; + + return n2; + } + + inline ListNode<Tp>() { } + + inline const ListNode<Tp> *at(int index) const { + const ListNode<Tp> *node = this; + while (index != node->index) + node = node->next; + + return node; + } + + inline bool hasNext() const { + return index < next->index; + } + + inline int count() const { + return 1 + toBack()->index; + } + + inline const ListNode<Tp> *toFront() const { + return toBack()->next; + } + + inline const ListNode<Tp> *toBack() const { + const ListNode<Tp> *node = this; + while (node->hasNext()) + node = node->next; + + return node; + } +}; + +template <class Tp> +inline const ListNode<Tp> *snoc(const ListNode<Tp> *list, + const Tp &element, pool *p) +{ + if (!list) + return ListNode<Tp>::create(element, p); + + return ListNode<Tp>::create(list->toBack(), element, p); +} + +#endif // FASTLIST_H + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/sources/shiboken2/ApiExtractor/parser/name_compiler.cpp b/sources/shiboken2/ApiExtractor/parser/name_compiler.cpp new file mode 100644 index 000000000..338d81c25 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/name_compiler.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** 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 "name_compiler.h" +#include "type_compiler.h" +#include "declarator_compiler.h" +#include "lexer.h" +#include "symbol.h" +#include "binder.h" + +#include <QtCore/qdebug.h> + +NameCompiler::NameCompiler(Binder *binder) + : _M_binder(binder), _M_token_stream(binder->tokenStream()) +{ +} + +QString NameCompiler::decode_operator(std::size_t index) const +{ + const Token &tk = _M_token_stream->token((int) index); + return QString::fromUtf8(&tk.text[tk.position], (int) tk.size); +} + +QString NameCompiler::internal_run(AST *node) +{ + _M_name.clear(); + visit(node); + return name(); +} + +void NameCompiler::visitUnqualifiedName(UnqualifiedNameAST *node) +{ + QString tmp_name; + + if (node->tilde) + tmp_name += QLatin1String("~"); + + if (node->id) + tmp_name += _M_token_stream->symbol(node->id)->as_string(); + + if (OperatorFunctionIdAST *op_id = node->operator_id) { +#if defined(__GNUC__) +#warning "NameCompiler::visitUnqualifiedName() -- implement me" +#endif + + if (op_id->op && op_id->op->op) { + tmp_name += QLatin1String("operator"); + tmp_name += decode_operator(op_id->op->op); + if (op_id->op->close) + tmp_name += decode_operator(op_id->op->close); + } else if (op_id->type_specifier) { +#if defined(__GNUC__) +#warning "don't use an hardcoded string as cast' name" +#endif + Token const &tk = _M_token_stream->token((int) op_id->start_token); + Token const &end_tk = _M_token_stream->token((int) op_id->end_token); + tmp_name += QString::fromLatin1(&tk.text[tk.position], + (int)(end_tk.position - tk.position)).trimmed(); + } + } + + _M_name += tmp_name; + if (node->template_arguments) { + // ### cleanup + _M_name.last() += QLatin1String("<"); + visitNodes(this, node->template_arguments); + _M_name.last().truncate(_M_name.last().count() - 1); // remove the last ',' + _M_name.last() += QLatin1String(">"); + } + +} + +void NameCompiler::visitTemplateArgument(TemplateArgumentAST *node) +{ + if (node->type_id && node->type_id->type_specifier) { + TypeCompiler type_cc(_M_binder); + type_cc.run(node->type_id->type_specifier); + + DeclaratorCompiler decl_cc(_M_binder); + decl_cc.run(node->type_id->declarator); + + if (type_cc.isConstant()) + _M_name.last() += QLatin1String("const "); + + QStringList q = type_cc.qualifiedName(); + + if (q.count() == 1) { +#if defined (RXX_RESOLVE_TYPEDEF) // ### it'll break :( + TypeInfo tp; + tp.setQualifiedName(q); + tp = TypeInfo::resolveType(tp, _M_binder->currentScope()->toItem()); + q = tp.qualifiedName(); +#endif + + if (CodeModelItem item = _M_binder->model()->findItem(q, _M_binder->currentScope())) { + if (item->name() == q.last()) + q = item->qualifiedName(); + } + } + + _M_name.last() += q.join(QLatin1String("::")); + + if (decl_cc.isReference()) + _M_name.last() += QLatin1Char('&'); + if (decl_cc.indirection()) + _M_name.last() += QString(decl_cc.indirection(), QLatin1Char('*')); + + _M_name.last() += QLatin1Char(','); + } +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/name_compiler.h b/sources/shiboken2/ApiExtractor/parser/name_compiler.h new file mode 100644 index 000000000..431d401f8 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/name_compiler.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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 NAME_COMPILER_H +#define NAME_COMPILER_H + +#include "default_visitor.h" +#include <QtCore/QStringList> + +class TokenStream; +class Binder; + +class NameCompiler: protected DefaultVisitor +{ +public: + NameCompiler(Binder *binder); + + void run(NameAST *node) { + internal_run(node); + } + void run(UnqualifiedNameAST *node) { + internal_run(node); + } + + QString name() const { + return _M_name.join(QLatin1String("::")); + } + QStringList qualifiedName() const { + return _M_name; + } + +protected: + virtual void visitUnqualifiedName(UnqualifiedNameAST *node); + virtual void visitTemplateArgument(TemplateArgumentAST *node); + + QString internal_run(AST *node); + QString decode_operator(std::size_t index) const; + +private: + Binder *_M_binder; + TokenStream *_M_token_stream; + QStringList _M_name; +}; + +#endif // NAME_COMPILER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/parser.cpp b/sources/shiboken2/ApiExtractor/parser/parser.cpp new file mode 100644 index 000000000..60d034e83 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/parser.cpp @@ -0,0 +1,4075 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + + +// c++ support +#include "parser.h" +#include "tokens.h" +#include "lexer.h" +#include "control.h" + +#include <cstdlib> + +#define ADVANCE(tk, descr) \ + { \ + if (token_stream.lookAhead() != tk) { \ + tokenRequiredError(tk); \ + return false; \ + } \ + token_stream.nextToken(); \ + } + +#define ADVANCE_NR(tk, descr) \ + do { \ + if (token_stream.lookAhead() != tk) { \ + tokenRequiredError(tk); \ + } \ + else \ + token_stream.nextToken(); \ + } while (0) + +#define CHECK(tk) \ + do { \ + if (token_stream.lookAhead() != tk) { \ + return false; \ + } \ + token_stream.nextToken(); \ + } while (0) + +#define UPDATE_POS(_node, start, end) \ + do { \ + (_node)->start_token = start; \ + (_node)->end_token = end; \ + } while (0) + +Parser::Parser(Control *c) + : _M_location(token_stream, location_table, line_table), + control(c), + lexer(_M_location, control) +{ + _M_block_errors = false; +} + +Parser::~Parser() +{ +} + +void Parser::advance() +{ + token_stream.nextToken(); +} + +TranslationUnitAST *Parser::parse(const char *contents, + std::size_t size, pool *p) +{ + _M_block_errors = false; + _M_pool = p; + lexer.tokenize(contents, size); + token_stream.nextToken(); // skip the first token + + Lexer *oldLexer = control->changeLexer(&lexer); + Parser *oldParser = control->changeParser(this); + + TranslationUnitAST *ast = 0; + parseTranslationUnit(ast); + + control->changeLexer(oldLexer); + control->changeParser(oldParser); + + return ast; +} + +bool Parser::parseWinDeclSpec(WinDeclSpecAST *&node) +{ + if (token_stream.lookAhead() != Token_identifier) + return false; + + std::size_t start = token_stream.cursor(); + + const NameSymbol *name_symbol = token_stream.symbol(token_stream.cursor()); + QString name = name_symbol->as_string(); + if (name != QLatin1String("__declspec")) + return false; + std::size_t specifier = token_stream.cursor(); + + token_stream.nextToken(); + if (token_stream.lookAhead() != '(') + return false; + + token_stream.nextToken(); + if (token_stream.lookAhead() != Token_identifier) + return false; + std::size_t modifier = token_stream.cursor(); + + token_stream.nextToken(); + if (token_stream.lookAhead() != ')') + return false; + + token_stream.nextToken(); + + node = CreateNode<WinDeclSpecAST>(_M_pool); + node->specifier = specifier; + node->modifier = modifier; + + UPDATE_POS(node, start, token_stream.cursor()); + + return true; +} + +void Parser::tokenRequiredError(int token) +{ + QString err; + + err += QLatin1String("expected token "); + err += QLatin1String("``"); + err += QLatin1String(token_name(token)); + err += QLatin1String("'' found ``"); + err += QLatin1String(token_name(token_stream.lookAhead())); + err += QLatin1String("''"); + + reportError(err); +} + +void Parser::syntaxError() +{ + QString err; + + err += QLatin1String("unexpected token "); + err += QLatin1String("``"); + err += QLatin1String(token_name(token_stream.lookAhead())); + err += QLatin1String("''"); + + reportError(err); +} + +void Parser::reportError(const QString& msg) +{ + if (!_M_block_errors) { + int line, column; + QString fileName; + + std::size_t tok = token_stream.cursor(); + location().positionAt(token_stream.position(tok), + &line, &column, &fileName); + + Control::ErrorMessage errmsg; + errmsg.setLine(line + 1); + errmsg.setColumn(column); + errmsg.setFileName(fileName); + errmsg.setMessage(QLatin1String("** PARSER ERROR ") + msg); + control->reportError(errmsg); + } +} + +bool Parser::skipUntil(int token) +{ + while (token_stream.lookAhead()) { + if (token_stream.lookAhead() == token) + return true; + + token_stream.nextToken(); + } + + return false; +} + +bool Parser::skipUntilDeclaration() +{ + while (token_stream.lookAhead()) { + + switch (token_stream.lookAhead()) { + case ';': + case '~': + case Token_scope: + case Token_identifier: + case Token_operator: + case Token_char: + case Token_wchar_t: + case Token_bool: + case Token_short: + case Token_int: + case Token_long: + case Token_signed: + case Token_unsigned: + case Token_float: + case Token_double: + case Token_void: + case Token_extern: + case Token_namespace: + case Token_using: + case Token_typedef: + case Token_asm: + case Token_template: + case Token_export: + + case Token_const: // cv + case Token_volatile: // cv + + case Token_public: + case Token_protected: + case Token_private: + case Token_signals: // Qt + case Token_slots: // Qt + return true; + + default: + token_stream.nextToken(); + } + } + + return false; +} + +bool Parser::skipUntilStatement() +{ + while (token_stream.lookAhead()) { + switch (token_stream.lookAhead()) { + case ';': + case '{': + case '}': + case Token_const: + case Token_volatile: + case Token_identifier: + case Token_case: + case Token_default: + case Token_if: + case Token_switch: + case Token_while: + case Token_do: + case Token_for: + case Token_break: + case Token_continue: + case Token_return: + case Token_goto: + case Token_try: + case Token_catch: + case Token_throw: + case Token_char: + case Token_wchar_t: + case Token_bool: + case Token_short: + case Token_int: + case Token_long: + case Token_signed: + case Token_unsigned: + case Token_float: + case Token_double: + case Token_void: + case Token_class: + case Token_struct: + case Token_union: + case Token_enum: + case Token_scope: + case Token_template: + case Token_using: + return true; + + default: + token_stream.nextToken(); + } + } + + return false; +} + +bool Parser::skip(int l, int r) +{ + int count = 0; + while (token_stream.lookAhead()) { + int tk = token_stream.lookAhead(); + + if (tk == l) + ++count; + else if (tk == r) + --count; + else if (l != '{' && (tk == '{' || tk == '}' || tk == ';')) + return false; + + if (!count) + return true; + + token_stream.nextToken(); + } + + return false; +} + +bool Parser::parseName(NameAST *&node, bool acceptTemplateId) +{ + std::size_t start = token_stream.cursor(); + + WinDeclSpecAST *winDeclSpec = 0; + parseWinDeclSpec(winDeclSpec); + + NameAST *ast = CreateNode<NameAST>(_M_pool); + + if (token_stream.lookAhead() == Token_scope) { + ast->global = true; + token_stream.nextToken(); + } + + std::size_t idx = token_stream.cursor(); + + while (true) { + UnqualifiedNameAST *n = 0; + if (!parseUnqualifiedName(n)) + return false; + + if (token_stream.lookAhead() == Token_scope) { + token_stream.nextToken(); + + ast->qualified_names + = snoc(ast->qualified_names, n, _M_pool); + + if (token_stream.lookAhead() == Token_template) { + /// skip optional template #### @todo CHECK + token_stream.nextToken(); + } + } else { + Q_ASSERT(n); + if (!acceptTemplateId) { + token_stream.rewind((int) n->start_token); + parseUnqualifiedName(n, false); + } + + ast->unqualified_name = n; + break; + } + } + + if (idx == token_stream.cursor()) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTranslationUnit(TranslationUnitAST *&node) +{ + std::size_t start = token_stream.cursor(); + TranslationUnitAST *ast = CreateNode<TranslationUnitAST>(_M_pool); + + while (token_stream.lookAhead()) { + std::size_t startDecl = token_stream.cursor(); + + DeclarationAST *declaration = 0; + if (parseDeclaration(declaration)) { + ast->declarations = + snoc(ast->declarations, declaration, _M_pool); + } else { + // error recovery + if (startDecl == token_stream.cursor()) { + // skip at least one token + token_stream.nextToken(); + } + + skipUntilDeclaration(); + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDeclaration(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case ';': + token_stream.nextToken(); + return true; + + case Token_extern: + return parseLinkageSpecification(node); + + case Token_namespace: + return parseNamespace(node); + + case Token_using: + return parseUsing(node); + + case Token_typedef: + return parseTypedef(node); + + case Token_asm: + return parseAsmDefinition(node); + + case Token_Q_ENUMS: + case Token_Q_ENUM: + // Qt5: + // These two Q_ENUM tokens map to the same handler. + // If that turns out to be wrong, then write a new one + // named parseQ_ENUM + return parseQ_ENUMS(node); + + case Token_template: + case Token_export: + return parseTemplateDeclaration(node); + + default: { + const ListNode<std::size_t> *cv = 0; + parseCvQualify(cv); + + const ListNode<std::size_t> *storageSpec = 0; + parseStorageClassSpecifier(storageSpec); + + parseCvQualify(cv); + + TypeSpecifierAST *spec = 0; + if (parseEnumSpecifier(spec) + || parseClassSpecifier(spec) + || parseForwardDeclarationSpecifier(spec)) { + parseCvQualify(cv); + + spec->cv = cv; + + const ListNode<InitDeclaratorAST*> *declarators = 0; + parseInitDeclaratorList(declarators); + ADVANCE(';', ";"); + + SimpleDeclarationAST *ast = + CreateNode<SimpleDeclarationAST>(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->type_specifier = spec; + ast->init_declarators = declarators; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + } // end switch + + token_stream.rewind((int) start); + return parseDeclarationInternal(node); +} + +bool Parser::parseLinkageSpecification(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_extern); + + LinkageSpecificationAST *ast = CreateNode<LinkageSpecificationAST>(_M_pool); + + if (token_stream.lookAhead() == Token_string_literal) { + ast->extern_type = token_stream.cursor(); + token_stream.nextToken(); + } + + if (token_stream.lookAhead() == '{') + parseLinkageBody(ast->linkage_body); + else if (!parseDeclaration(ast->declaration)) + reportError(QLatin1String("Declaration syntax error")); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseLinkageBody(LinkageBodyAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK('{'); + + LinkageBodyAST *ast = CreateNode<LinkageBodyAST>(_M_pool); + + while (token_stream.lookAhead()) { + int tk = token_stream.lookAhead(); + + if (tk == '}') + break; + + std::size_t startDecl = token_stream.cursor(); + + DeclarationAST *declaration = 0; + if (parseDeclaration(declaration)) { + ast->declarations = snoc(ast->declarations, declaration, _M_pool); + } else { + // error recovery + if (startDecl == token_stream.cursor()) { + // skip at least one token + token_stream.nextToken(); + } + + skipUntilDeclaration(); + } + } + + if (token_stream.lookAhead() != '}') + reportError(QLatin1String("} expected")); + else + token_stream.nextToken(); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNamespace(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_namespace); + + std::size_t namespace_name = 0; + if (token_stream.lookAhead() == Token_identifier) { + namespace_name = token_stream.cursor(); + token_stream.nextToken(); + } + + if (token_stream.lookAhead() == '=') { + // namespace alias + token_stream.nextToken(); + + NameAST *name = 0; + if (parseName(name)) { + ADVANCE(';', ";"); + + NamespaceAliasDefinitionAST *ast + = CreateNode<NamespaceAliasDefinitionAST>(_M_pool); + ast->namespace_name = namespace_name; + ast->alias_name = name; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; + } else { + reportError(QLatin1String("namespace expected")); + return false; + } + } else if (token_stream.lookAhead() != '{') { + reportError(QLatin1String("{ expected")); + return false; + } + + NamespaceAST *ast = CreateNode<NamespaceAST>(_M_pool); + ast->namespace_name = namespace_name; + parseLinkageBody(ast->linkage_body); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseUsing(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_using); + + if (token_stream.lookAhead() == Token_namespace) + return parseUsingDirective(node); + + UsingAST *ast = CreateNode<UsingAST>(_M_pool); + + if (token_stream.lookAhead() == Token_typename) { + ast->type_name = token_stream.cursor(); + token_stream.nextToken(); + } + + if (!parseName(ast->name)) + return false; + + ADVANCE(';', ";"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseUsingDirective(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_namespace); + + NameAST *name = 0; + if (!parseName(name)) { + reportError(QLatin1String("Namespace name expected")); + return false; + } + + ADVANCE(';', ";"); + + UsingDirectiveAST *ast = CreateNode<UsingDirectiveAST>(_M_pool); + ast->name = name; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + + +bool Parser::parseOperatorFunctionId(OperatorFunctionIdAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_operator); + + OperatorFunctionIdAST *ast = CreateNode<OperatorFunctionIdAST>(_M_pool); + + if (!parseOperator(ast->op)) { + ast->op = 0; + + // parse cast operator + const ListNode<std::size_t> *cv = 0; + parseCvQualify(cv); + + if (!parseSimpleTypeSpecifier(ast->type_specifier)) { + syntaxError(); + return false; + } + + parseCvQualify(cv); + ast->type_specifier->cv = cv; + + PtrOperatorAST *ptr_op = 0; + while (parsePtrOperator(ptr_op)) + ast->ptr_ops = snoc(ast->ptr_ops, ptr_op, _M_pool); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; +} + +bool Parser::parseTemplateArgumentList(const ListNode<TemplateArgumentAST*> *&node, + bool reportError) +{ + TemplateArgumentAST *templArg = 0; + if (!parseTemplateArgument(templArg)) + return false; + + node = snoc(node, templArg, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseTemplateArgument(templArg)) { + if (reportError) { + syntaxError(); + break; + } + + node = 0; + return false; + } + + node = snoc(node, templArg, _M_pool); + } + + return true; +} + +bool Parser::parseTypedef(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_typedef); + + TypeSpecifierAST *spec = 0; + if (!parseTypeSpecifierOrClassSpec(spec)) { + reportError(QLatin1String("Need a type specifier to declare")); + return false; + } + + const ListNode<InitDeclaratorAST*> *declarators = 0; + if (!parseInitDeclaratorList(declarators)) { + //reportError(("Need an identifier to declare")); + //return false; + } + + ADVANCE(';', ";"); + + TypedefAST *ast = CreateNode<TypedefAST>(_M_pool); + ast->type_specifier = spec; + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseAsmDefinition(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_asm, "asm"); + + const ListNode<std::size_t> *cv = 0; + parseCvQualify(cv); + +#if defined(__GNUC__) +#warning "implement me" +#endif + skip('(', ')'); + token_stream.nextToken(); + ADVANCE(';', ";"); + + AsmDefinitionAST *ast = CreateNode<AsmDefinitionAST>(_M_pool); + ast->cv = cv; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTemplateDeclaration(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + std::size_t exported = 0; + if (token_stream.lookAhead() == Token_export) { + exported = token_stream.cursor(); + token_stream.nextToken(); + } + + CHECK(Token_template); + + const ListNode<TemplateParameterAST*> *params = 0; + if (token_stream.lookAhead() == '<') { + token_stream.nextToken(); + parseTemplateParameterList(params); + + ADVANCE('>', ">"); + } + + DeclarationAST *declaration = 0; + if (!parseDeclaration(declaration)) + reportError(QLatin1String("expected a declaration")); + + TemplateDeclarationAST *ast = CreateNode<TemplateDeclarationAST>(_M_pool); + ast->exported = exported; + ast->template_parameters = params; + ast->declaration = declaration; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseOperator(OperatorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + OperatorAST *ast = CreateNode<OperatorAST>(_M_pool); + + switch (token_stream.lookAhead()) { + case Token_new: + case Token_delete: { + ast->op = token_stream.cursor(); + token_stream.nextToken(); + + if (token_stream.lookAhead() == '[' + && token_stream.lookAhead(1) == ']') { + ast->open = token_stream.cursor(); + token_stream.nextToken(); + + ast->close = token_stream.cursor(); + token_stream.nextToken(); + } + } + break; + + case '+': + case '-': + case '*': + case '/': + case '%': + case '^': + case '&': + case '|': + case '~': + case '!': + case '=': + case '<': + case '>': + case ',': + case Token_assign: + case Token_shift: + case Token_eq: + case Token_not_eq: + case Token_leq: + case Token_geq: + case Token_and: + case Token_or: + case Token_incr: + case Token_decr: + case Token_ptrmem: + case Token_arrow: + ast->op = token_stream.cursor(); + token_stream.nextToken(); + break; + + default: + if (token_stream.lookAhead() == '(' + && token_stream.lookAhead(1) == ')') { + ast->op = ast->open = token_stream.cursor(); + token_stream.nextToken(); + ast->close = token_stream.cursor(); + token_stream.nextToken(); + } else if (token_stream.lookAhead() == '[' + && token_stream.lookAhead(1) == ']') { + ast->op = ast->open = token_stream.cursor(); + token_stream.nextToken(); + ast->close = token_stream.cursor(); + token_stream.nextToken(); + } else { + return false; + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseCvQualify(const ListNode<std::size_t> *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk; + while (0 != (tk = token_stream.lookAhead()) + && (tk == Token_const || tk == Token_volatile)) { + node = snoc(node, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + } + + return start != token_stream.cursor(); +} + +bool Parser::parseSimpleTypeSpecifier(TypeSpecifierAST *&node, + bool onlyIntegral) +{ + std::size_t start = token_stream.cursor(); + bool isIntegral = false; + bool done = false; + + const ListNode<std::size_t> *integrals = 0; + + while (!done) { + switch (token_stream.lookAhead()) { + case Token_char: + case Token_wchar_t: + case Token_bool: + case Token_short: + case Token_int: + case Token_long: + case Token_signed: + case Token_unsigned: + case Token_float: + case Token_double: + case Token_void: + integrals = snoc(integrals, token_stream.cursor(), _M_pool); + isIntegral = true; + token_stream.nextToken(); + break; + + default: + done = true; + } + } + + SimpleTypeSpecifierAST *ast = CreateNode<SimpleTypeSpecifierAST>(_M_pool); + if (isIntegral) { + ast->integrals = integrals; + } else if (token_stream.lookAhead() == Token___typeof) { + ast->type_of = token_stream.cursor(); + token_stream.nextToken(); + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + std::size_t saved = token_stream.cursor(); + parseTypeId(ast->type_id); + if (token_stream.lookAhead() != ')') { + ast->type_id = 0; + token_stream.rewind((int) saved); + parseUnaryExpression(ast->expression); + } + ADVANCE(')', ")"); + } else { + parseUnaryExpression(ast->expression); + } + } else if (onlyIntegral) { + token_stream.rewind((int) start); + return false; + } else { + if (!parseName(ast->name, true)) { + ast->name = 0; + token_stream.rewind((int) start); + return false; + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parsePtrOperator(PtrOperatorAST *&node) +{ + int tk = token_stream.lookAhead(); + + if (tk != '&' && tk != '*' + && tk != Token_scope && tk != Token_identifier) { + return false; + } + + std::size_t start = token_stream.cursor(); + + PtrOperatorAST *ast = CreateNode<PtrOperatorAST>(_M_pool); + + switch (token_stream.lookAhead()) { + case '&': + case '*': + ast->op = token_stream.cursor(); + token_stream.nextToken(); + break; + + case Token_scope: + case Token_identifier: { + if (!parsePtrToMember(ast->mem_ptr)) { + token_stream.rewind((int) start); + return false; + } + } + break; + + default: + Q_ASSERT(0); + break; + } + + parseCvQualify(ast->cv); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTemplateArgument(TemplateArgumentAST *&node) +{ + std::size_t start = token_stream.cursor(); + + TypeIdAST *typeId = 0; + ExpressionAST *expr = 0; + + if (!parseTypeId(typeId) || (token_stream.lookAhead() != ',' + && token_stream.lookAhead() != '>')) { + token_stream.rewind((int) start); + + if (!parseLogicalOrExpression(expr, true)) + return false; + } + + TemplateArgumentAST *ast = CreateNode<TemplateArgumentAST>(_M_pool); + ast->type_id = typeId; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTypeSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + const ListNode<std::size_t> *cv = 0; + parseCvQualify(cv); + + TypeSpecifierAST *ast = 0; + if (!parseElaboratedTypeSpecifier(ast) && !parseSimpleTypeSpecifier(ast)) { + token_stream.rewind((int) start); + return false; + } + + parseCvQualify(cv); + ast->cv = cv; + + node = ast; + + return true; +} + +bool Parser::parseDeclarator(DeclaratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeclaratorAST *ast = CreateNode<DeclaratorAST>(_M_pool); + + //fprintf(stderr, "[%s-%s] ast->ptr_ops: %p\n", __FILE__, __FUNCTION__, ast->ptr_ops); + + DeclaratorAST *decl = 0; + NameAST *declId = 0; + + PtrOperatorAST *ptrOp = 0; + while (parsePtrOperator(ptrOp)) + ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, _M_pool); + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + if (!parseDeclarator(decl)) + return false; + + ast->sub_declarator = decl; + + CHECK(')'); + } else { + if (token_stream.lookAhead() == ':') { + // unnamed bitfield + } else if (parseName(declId, true)) { + ast->id = declId; + } else { + token_stream.rewind((int) start); + return false; + } + + if (token_stream.lookAhead() == ':') { + token_stream.nextToken(); + + if (!parseConstantExpression(ast->bit_expression)) + reportError(QLatin1String("Constant expression expected")); + + goto update_pos; + } + } + + { + bool isVector = true; + + while (token_stream.lookAhead() == '[') { + token_stream.nextToken(); + + ExpressionAST *expr = 0; + parseCommaExpression(expr); + + ADVANCE(']', "]"); + + ast->array_dimensions = snoc(ast->array_dimensions, expr, _M_pool); + isVector = true; + } + + bool skipParen = false; + if (token_stream.lookAhead() == Token_identifier + && token_stream.lookAhead(1) == '(' + && token_stream.lookAhead(2) == '(') { + token_stream.nextToken(); + token_stream.nextToken(); + skipParen = true; + } + + int tok = token_stream.lookAhead(); + if (ast->sub_declarator + && !(isVector || tok == '(' || tok == ',' + || tok == ';' || tok == '=')) { + token_stream.rewind((int) start); + return false; + } + + std::size_t index = token_stream.cursor(); + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + ParameterDeclarationClauseAST *params = 0; + if (!parseParameterDeclarationClause(params)) { + token_stream.rewind((int) index); + goto update_pos; + } + + ast->parameter_declaration_clause = params; + + if (token_stream.lookAhead() != ')') { + token_stream.rewind((int) index); + goto update_pos; + } + + token_stream.nextToken(); // skip ')' + + parseCvQualify(ast->fun_cv); + parseNoExcept(); + parseExceptionSpecification(ast->exception_spec); + + if (token_stream.lookAhead() == Token___attribute__) + parse_Attribute__(); + } + + if (skipParen) { + if (token_stream.lookAhead() != ')') + reportError(QLatin1String("')' expected")); + else + token_stream.nextToken(); + } + } + +update_pos: + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseAbstractDeclarator(DeclaratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeclaratorAST *ast = CreateNode<DeclaratorAST>(_M_pool); + DeclaratorAST *decl = 0; + + PtrOperatorAST *ptrOp = 0; + while (parsePtrOperator(ptrOp)) + ast->ptr_ops = snoc(ast->ptr_ops, ptrOp, _M_pool); + + int index = (int) token_stream.cursor(); + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + if (!parseAbstractDeclarator(decl)) { + token_stream.rewind((int) index); + goto label1; + } + + ast->sub_declarator = decl; + + if (token_stream.lookAhead() != ')') { + token_stream.rewind((int) start); + return false; + } + token_stream.nextToken(); + } else if (token_stream.lookAhead() == ':') { + token_stream.nextToken(); + if (!parseConstantExpression(ast->bit_expression)) { + ast->bit_expression = 0; + reportError(QLatin1String("Constant expression expected")); + } + goto update_pos; + } + +label1: { + bool isVector = true; + + while (token_stream.lookAhead() == '[') { + token_stream.nextToken(); + + ExpressionAST *expr = 0; + parseCommaExpression(expr); + + ADVANCE(']', "]"); + + ast->array_dimensions = snoc(ast->array_dimensions, expr, _M_pool); + isVector = true; + } + + int tok = token_stream.lookAhead(); + if (ast->sub_declarator + && !(isVector || tok == '(' || tok == ',' + || tok == ';' || tok == '=')) { + token_stream.rewind((int) start); + return false; + } + + int index = (int) token_stream.cursor(); + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + ParameterDeclarationClauseAST *params = 0; + if (!parseParameterDeclarationClause(params)) { + token_stream.rewind((int) index); + goto update_pos; + } + + ast->parameter_declaration_clause = params; + + if (token_stream.lookAhead() != ')') { + token_stream.rewind((int) index); + goto update_pos; + } + + token_stream.nextToken(); // skip ')' + + parseCvQualify(ast->fun_cv); + parseExceptionSpecification(ast->exception_spec); + } + } + +update_pos: + if (token_stream.cursor() == start) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseEnumSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_enum); + + NameAST *name = 0; + parseName(name); + + if (token_stream.lookAhead() != '{') { + token_stream.rewind((int) start); + return false; + } + token_stream.nextToken(); + + EnumSpecifierAST *ast = CreateNode<EnumSpecifierAST>(_M_pool); + ast->name = name; + + EnumeratorAST *enumerator = 0; + if (parseEnumerator(enumerator)) { + ast->enumerators = snoc(ast->enumerators, enumerator, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseEnumerator(enumerator)) { + //reportError(("Enumerator expected")); + break; + } + + ast->enumerators = snoc(ast->enumerators, enumerator, _M_pool); + } + } + + ADVANCE_NR('}', "}"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTemplateParameterList(const ListNode<TemplateParameterAST*> *&node) +{ + TemplateParameterAST *param = 0; + if (!parseTemplateParameter(param)) + return false; + + node = snoc(node, param, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseTemplateParameter(param)) { + syntaxError(); + break; + } else { + node = snoc(node, param, _M_pool); + } + } + + return true; +} + +bool Parser::parseTemplateParameter(TemplateParameterAST *&node) +{ + std::size_t start = token_stream.cursor(); + TemplateParameterAST *ast = CreateNode<TemplateParameterAST>(_M_pool); + + int tk = token_stream.lookAhead(); + + if ((tk == Token_class || tk == Token_typename || tk == Token_template) + && parseTypeParameter(ast->type_parameter)) { + // nothing to do + } else if (!parseParameterDeclaration(ast->parameter_declaration)) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTypeParameter(TypeParameterAST *&node) +{ + std::size_t start = token_stream.cursor(); + + TypeParameterAST *ast = CreateNode<TypeParameterAST>(_M_pool); + ast->type = start; + + switch (token_stream.lookAhead()) { + case Token_class: + case Token_typename: { + token_stream.nextToken(); // skip class + + // parse optional name + if (parseName(ast->name, true)) { + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + if (!parseTypeId(ast->type_id)) { + //syntaxError(); + token_stream.rewind((int) start); + return false; + } + } else if (token_stream.lookAhead() != ',' + && token_stream.lookAhead() != '>') { + token_stream.rewind((int) start); + return false; + } + } + } + break; + + case Token_template: { + token_stream.nextToken(); // skip template + ADVANCE('<', "<"); + + if (!parseTemplateParameterList(ast->template_parameters)) + return false; + + ADVANCE('>', ">"); + + if (token_stream.lookAhead() == Token_class) + token_stream.nextToken(); + + // parse optional name + if (parseName(ast->name, true)) { + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + if (!parseTypeId(ast->type_id)) { + syntaxError(); + return false; + } + } + } + + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + parseName(ast->template_name, true); + } + } + break; + + default: + return false; + + } // end switch + + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; +} + +bool Parser::parseStorageClassSpecifier(const ListNode<std::size_t> *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk; + while (0 != (tk = token_stream.lookAhead()) + && (tk == Token_friend || tk == Token_auto + || tk == Token_register || tk == Token_static + || tk == Token_extern || tk == Token_mutable)) { + node = snoc(node, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + } + + return start != token_stream.cursor(); +} + +bool Parser::parseFunctionSpecifier(const ListNode<std::size_t> *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk; + while (0 != (tk = token_stream.lookAhead()) + && (tk == Token_inline || tk == Token_virtual + || tk == Token_explicit || tk == Token_Q_INVOKABLE)) { + node = snoc(node, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + } + + return start != token_stream.cursor(); +} + +bool Parser::parseTypeId(TypeIdAST *&node) +{ + /// @todo implement the AST for typeId + std::size_t start = token_stream.cursor(); + + TypeSpecifierAST *spec = 0; + if (!parseTypeSpecifier(spec)) { + token_stream.rewind((int) start); + return false; + } + + DeclaratorAST *decl = 0; + parseAbstractDeclarator(decl); + + TypeIdAST *ast = CreateNode<TypeIdAST>(_M_pool); + ast->type_specifier = spec; + ast->declarator = decl; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node) +{ + InitDeclaratorAST *decl = 0; + if (!parseInitDeclarator(decl)) + return false; + + node = snoc(node, decl, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseInitDeclarator(decl)) { + syntaxError(); + break; + } + node = snoc(node, decl, _M_pool); + } + + return true; +} + +bool Parser::parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ParameterDeclarationClauseAST *ast + = CreateNode<ParameterDeclarationClauseAST>(_M_pool); + + if (!parseParameterDeclarationList(ast->parameter_declarations)) { + if (token_stream.lookAhead() == ')') + goto good; + + if (token_stream.lookAhead() == Token_ellipsis + && token_stream.lookAhead(1) == ')') { + ast->ellipsis = token_stream.cursor(); + goto good; + } + + return false; + } + +good: + + if (token_stream.lookAhead() == Token_ellipsis) { + ast->ellipsis = token_stream.cursor(); + token_stream.nextToken(); + } + + /// @todo add ellipsis + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseParameterDeclarationList(const ListNode<ParameterDeclarationAST*> *&node) +{ + std::size_t start = token_stream.cursor(); + + ParameterDeclarationAST *param = 0; + if (!parseParameterDeclaration(param)) { + token_stream.rewind((int) start); + return false; + } + + node = snoc(node, param, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (token_stream.lookAhead() == Token_ellipsis) + break; + + if (!parseParameterDeclaration(param)) { + token_stream.rewind((int) start); + return false; + } + node = snoc(node, param, _M_pool); + } + + return true; +} + +bool Parser::parseParameterDeclaration(ParameterDeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + const ListNode<std::size_t> *storage = 0; + parseStorageClassSpecifier(storage); + + // parse decl spec + TypeSpecifierAST *spec = 0; + if (!parseTypeSpecifier(spec)) { + token_stream.rewind((int) start); + return false; + } + + int index = (int) token_stream.cursor(); + + DeclaratorAST *decl = 0; + if (!parseDeclarator(decl)) { + token_stream.rewind((int) index); + + // try with abstract declarator + parseAbstractDeclarator(decl); + } + + ExpressionAST *expr = 0; + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + if (!parseLogicalOrExpression(expr, true)) + reportError(QLatin1String("Expression expected")); + } + + ParameterDeclarationAST *ast = CreateNode<ParameterDeclarationAST>(_M_pool); + ast->type_specifier = spec; + ast->declarator = decl; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parse_Attribute__() +{ + token_stream.nextToken(); + + ADVANCE('(', "("); + + ExpressionAST *expr = 0; + parseExpression(expr); + + if (token_stream.lookAhead() != ')') { + reportError(QLatin1String("')' expected")); + return false; + } else { + token_stream.nextToken(); + } + return true; +} + +QString Parser::tokenText(AST *ast) const +{ + if (!ast) + return QString(); + + int start_token = ast->start_token; + int end_token = ast->end_token; + + Token const &tk = token_stream.token(start_token); + Token const &end_tk = token_stream.token(end_token); + + return QString::fromLatin1(&tk.text[tk.position], + (int)(end_tk.position - tk.position)).trimmed(); +} + +bool Parser::parseForwardDeclarationSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + int kind = token_stream.lookAhead(); + if (kind != Token_class && kind != Token_struct && kind != Token_union) + return false; + + std::size_t class_key = token_stream.cursor(); + token_stream.nextToken(); + + NameAST *name = 0; + if (!parseName(name, false)) { + token_stream.rewind((int) start); + return false; + } + + BaseClauseAST *bases = 0; + if (token_stream.lookAhead() == ':') { + if (!parseBaseClause(bases)) { + token_stream.rewind((int) start); + return false; + } + } + + if (token_stream.lookAhead() != ';') { + token_stream.rewind((int) start); + return false; + } + + ForwardDeclarationSpecifierAST *ast = CreateNode<ForwardDeclarationSpecifierAST>(_M_pool); + ast->class_key = class_key; + ast->name = name; + ast->base_clause = bases; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseClassSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + int kind = token_stream.lookAhead(); + if (kind != Token_class && kind != Token_struct && kind != Token_union) + return false; + + std::size_t class_key = token_stream.cursor(); + token_stream.nextToken(); + + WinDeclSpecAST *winDeclSpec = 0; + parseWinDeclSpec(winDeclSpec); + + if (token_stream.lookAhead() == Token___attribute__) + parse_Attribute__(); + + while (token_stream.lookAhead() == Token_identifier + && token_stream.lookAhead(1) == Token_identifier) + token_stream.nextToken(); + + NameAST *name = 0; + parseName(name, true); + + BaseClauseAST *bases = 0; + + if (token_stream.lookAhead() == ':') { + if (!parseBaseClause(bases)) + skipUntil('{'); + } + + if (token_stream.lookAhead() != '{') { + + token_stream.rewind((int) start); + return false; + } + + ADVANCE('{', "{"); + + ClassSpecifierAST *ast = CreateNode<ClassSpecifierAST>(_M_pool); + ast->win_decl_specifiers = winDeclSpec; + ast->class_key = class_key; + ast->name = name; + ast->base_clause = bases; + + while (token_stream.lookAhead()) { + if (token_stream.lookAhead() == '}') + break; + + std::size_t startDecl = token_stream.cursor(); + + DeclarationAST *memSpec = 0; + if (!parseMemberSpecification(memSpec)) { + if (startDecl == token_stream.cursor()) + token_stream.nextToken(); // skip at least one token + skipUntilDeclaration(); + } else + ast->member_specs = snoc(ast->member_specs, memSpec, _M_pool); + } + + ADVANCE_NR('}', "}"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseAccessSpecifier(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + const ListNode<std::size_t> *specs = 0; + + bool done = false; + while (!done) { + switch (token_stream.lookAhead()) { + case Token_signals: + case Token_slots: + case Token_k_dcop: + case Token_k_dcop_signals: + case Token_public: + case Token_protected: + case Token_private: + specs = snoc(specs, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + break; + + default: + done = true; + break; + } + } + + if (!specs) + return false; + + ADVANCE(':', ":"); + + AccessSpecifierAST *ast = CreateNode<AccessSpecifierAST>(_M_pool); + ast->specs = specs; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseMemberSpecification(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() == ';') { + token_stream.nextToken(); + return true; + } else if (token_stream.lookAhead() == Token_Q_OBJECT + || token_stream.lookAhead() == Token_K_DCOP) { + token_stream.nextToken(); + return true; + } else if (parseTypedef(node)) { + return true; + } else if (parseUsing(node)) { + return true; + } else if (parseTemplateDeclaration(node)) { + return true; + } else if (parseAccessSpecifier(node)) { + return true; + } else if (parseQ_PROPERTY(node)) { + return true; + } else if (parseQ_ENUMS(node)) { + return true; + } + + token_stream.rewind((int) start); + + const ListNode<std::size_t> *cv = 0; + parseCvQualify(cv); + + const ListNode<std::size_t> *storageSpec = 0; + parseStorageClassSpecifier(storageSpec); + + parseCvQualify(cv); + + TypeSpecifierAST *spec = 0; + if (parseEnumSpecifier(spec) || parseClassSpecifier(spec)) { + parseCvQualify(cv); + spec->cv = cv; + + const ListNode<InitDeclaratorAST*> *declarators = 0; + parseInitDeclaratorList(declarators); + ADVANCE(';', ";"); + + SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool); + ast->type_specifier = spec; + ast->init_declarators = declarators; + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + + token_stream.rewind((int) start); + return parseDeclarationInternal(node); +} + +bool Parser::parseCtorInitializer(CtorInitializerAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(':'); + + CtorInitializerAST *ast = CreateNode<CtorInitializerAST>(_M_pool); + ast->colon = start; + + if (!parseMemInitializerList(ast->member_initializers)) + reportError(QLatin1String("Member initializers expected")); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseElaboratedTypeSpecifier(TypeSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk = token_stream.lookAhead(); + if (tk == Token_class + || tk == Token_struct + || tk == Token_union + || tk == Token_enum + || tk == Token_typename) { + std::size_t type = token_stream.cursor(); + token_stream.nextToken(); + + NameAST *name = 0; + if (parseName(name, true)) { + ElaboratedTypeSpecifierAST *ast + = CreateNode<ElaboratedTypeSpecifierAST>(_M_pool); + + ast->type = type; + ast->name = name; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + + token_stream.rewind((int) start); + return false; +} + +bool Parser::parseNoExcept() +{ + // right now we only accept 'noexcept' with no conditional + CHECK(Token_noexcept); + + return true; +} + +bool Parser::parseExceptionSpecification(ExceptionSpecificationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_throw); + ADVANCE('(', "("); + + ExceptionSpecificationAST *ast = CreateNode<ExceptionSpecificationAST>(_M_pool); + + if (token_stream.lookAhead() == Token_ellipsis) { + ast->ellipsis = token_stream.cursor(); + token_stream.nextToken(); + } else { + parseTypeIdList(ast->type_ids); + } + + ADVANCE(')', ")"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseEnumerator(EnumeratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_identifier); + std::size_t id = token_stream.cursor() - 1; + + EnumeratorAST *ast = CreateNode<EnumeratorAST>(_M_pool); + ast->id = id; + + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + if (!parseConstantExpression(ast->expression)) + reportError(QLatin1String("Constant expression expected")); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseInitDeclarator(InitDeclaratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeclaratorAST *decl = 0; + if (!parseDeclarator(decl)) + return false; + + if (token_stream.lookAhead(0) == Token_asm) { + token_stream.nextToken(); + skip('(', ')'); + token_stream.nextToken(); + } + + InitializerAST *init = 0; + parseInitializer(init); + + InitDeclaratorAST *ast = CreateNode<InitDeclaratorAST>(_M_pool); + ast->declarator = decl; + ast->initializer = init; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseBaseClause(BaseClauseAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(':'); + + BaseSpecifierAST *baseSpec = 0; + if (!parseBaseSpecifier(baseSpec)) + return false; + + BaseClauseAST *ast = CreateNode<BaseClauseAST>(_M_pool); + ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseBaseSpecifier(baseSpec)) { + reportError(QLatin1String("Base class specifier expected")); + break; + } + ast->base_specifiers = snoc(ast->base_specifiers, baseSpec, _M_pool); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseInitializer(InitializerAST *&node) +{ + std::size_t start = token_stream.cursor(); + + int tk = token_stream.lookAhead(); + if (tk != '=' && tk != '(') + return false; + + InitializerAST *ast = CreateNode<InitializerAST>(_M_pool); + + if (tk == '=') { + token_stream.nextToken(); + + if (!parseInitializerClause(ast->initializer_clause)) + reportError(QLatin1String("Initializer clause expected")); + + } else if (tk == '(') { + token_stream.nextToken(); + parseCommaExpression(ast->expression); + CHECK(')'); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseMemInitializerList(const ListNode<MemInitializerAST*> *&node) +{ + MemInitializerAST *init = 0; + + if (!parseMemInitializer(init)) + return false; + + node = snoc(node, init, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + + if (!parseMemInitializer(init)) + break; + + node = snoc(node, init, _M_pool); + } + + return true; +} + +bool Parser::parseMemInitializer(MemInitializerAST *&node) +{ + std::size_t start = token_stream.cursor(); + + NameAST *initId = 0; + if (!parseName(initId, true)) { + reportError(QLatin1String("Identifier expected")); + return false; + } + + ADVANCE('(', "("); + ExpressionAST *expr = 0; + parseCommaExpression(expr); + ADVANCE(')', ")"); + + MemInitializerAST *ast = CreateNode<MemInitializerAST>(_M_pool); + ast->initializer_id = initId; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseTypeIdList(const ListNode<TypeIdAST*> *&node) +{ + TypeIdAST *typeId = 0; + if (!parseTypeId(typeId)) + return false; + + node = snoc(node, typeId, _M_pool); + + while (token_stream.lookAhead() == ',') { + token_stream.nextToken(); + if (parseTypeId(typeId)) { + node = snoc(node, typeId, _M_pool); + } else { + reportError(QLatin1String("Type id expected")); + break; + } + } + + return true; +} + +bool Parser::parseBaseSpecifier(BaseSpecifierAST *&node) +{ + std::size_t start = token_stream.cursor(); + + BaseSpecifierAST *ast = CreateNode<BaseSpecifierAST>(_M_pool); + + if (token_stream.lookAhead() == Token_virtual) { + ast->virt = token_stream.cursor(); + token_stream.nextToken(); + + int tk = token_stream.lookAhead(); + if (tk == Token_public || tk == Token_protected + || tk == Token_private) { + ast->access_specifier = token_stream.cursor(); + token_stream.nextToken(); + } + } else { + int tk = token_stream.lookAhead(); + if (tk == Token_public || tk == Token_protected + || tk == Token_private) { + ast->access_specifier = token_stream.cursor(); + token_stream.nextToken(); + } + + if (token_stream.lookAhead() == Token_virtual) { + ast->virt = token_stream.cursor(); + token_stream.nextToken(); + } + } + + if (!parseName(ast->name, true)) + reportError(QLatin1String("Class name expected")); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseInitializerClause(InitializerClauseAST *&node) +{ + std::size_t start = token_stream.cursor(); + + InitializerClauseAST *ast = CreateNode<InitializerClauseAST>(_M_pool); + + if (token_stream.lookAhead() == '{') { +#if defined(__GNUC__) +#warning "implement me" +#endif + if (skip('{', '}')) + token_stream.nextToken(); + else + reportError(QLatin1String("} missing")); + } else { + if (!parseAssignmentExpression(ast->expression)) + reportError(QLatin1String("Expression expected")); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parsePtrToMember(PtrToMemberAST *&node) +{ +#if defined(__GNUC__) +#warning "implemente me (AST)" +#endif + + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() == Token_scope) { + token_stream.nextToken(); + } + + UnqualifiedNameAST *name = 0; + while (token_stream.lookAhead() == Token_identifier) { + if (!parseUnqualifiedName(name)) + break; + + if (token_stream.lookAhead() == Token_scope + && token_stream.lookAhead(1) == '*') { + token_stream.nextToken(); + token_stream.nextToken(); + + PtrToMemberAST *ast = CreateNode<PtrToMemberAST>(_M_pool); + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + + if (token_stream.lookAhead() == Token_scope) + token_stream.nextToken(); + } + + token_stream.rewind((int) start); + return false; +} + +bool Parser::parseUnqualifiedName(UnqualifiedNameAST *&node, + bool parseTemplateId) +{ + std::size_t start = token_stream.cursor(); + + std::size_t tilde = 0; + std::size_t id = 0; + OperatorFunctionIdAST *operator_id = 0; + + if (token_stream.lookAhead() == Token_identifier) { + id = token_stream.cursor(); + token_stream.nextToken(); + } else if (token_stream.lookAhead() == '~' + && token_stream.lookAhead(1) == Token_identifier) { + tilde = token_stream.cursor(); + token_stream.nextToken(); // skip ~ + + id = token_stream.cursor(); + token_stream.nextToken(); // skip classname + } else if (token_stream.lookAhead() == Token_operator) { + if (!parseOperatorFunctionId(operator_id)) + return false; + } else { + return false; + } + + UnqualifiedNameAST *ast = CreateNode<UnqualifiedNameAST>(_M_pool); + ast->tilde = tilde; + ast->id = id; + ast->operator_id = operator_id; + + if (parseTemplateId && !tilde) { + std::size_t index = token_stream.cursor(); + + if (token_stream.lookAhead() == '<') { + token_stream.nextToken(); + + // optional template arguments + parseTemplateArgumentList(ast->template_arguments); + + if (token_stream.lookAhead() == '>') { + token_stream.nextToken(); + } else { + ast->template_arguments = 0; + token_stream.rewind((int) index); + } + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseStringLiteral(StringLiteralAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() != Token_string_literal) + return false; + + StringLiteralAST *ast = CreateNode<StringLiteralAST>(_M_pool); + + while (token_stream.lookAhead() == Token_string_literal) { + ast->literals = snoc(ast->literals, token_stream.cursor(), _M_pool); + token_stream.nextToken(); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseExpressionStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ExpressionAST *expr = 0; + parseCommaExpression(expr); + + ADVANCE(';', ";"); + + ExpressionStatementAST *ast = CreateNode<ExpressionStatementAST>(_M_pool); + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case Token_while: + return parseWhileStatement(node); + + case Token_do: + return parseDoStatement(node); + + case Token_for: + return parseForStatement(node); + + case Token_if: + return parseIfStatement(node); + + case Token_switch: + return parseSwitchStatement(node); + + case Token_try: + return parseTryBlockStatement(node); + + case Token_case: + case Token_default: + return parseLabeledStatement(node); + + case Token_break: + case Token_continue: +#if defined(__GNUC__) +#warning "implement me" +#endif + token_stream.nextToken(); + ADVANCE(';', ";"); + return true; + + case Token_goto: +#if defined(__GNUC__) +#warning "implement me" +#endif + token_stream.nextToken(); + ADVANCE(Token_identifier, "identifier"); + ADVANCE(';', ";"); + return true; + + case Token_return: { + token_stream.nextToken(); + ExpressionAST *expr = 0; + parseCommaExpression(expr); + + ADVANCE(';', ";"); + + ReturnStatementAST *ast = CreateNode<ReturnStatementAST>(_M_pool); + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case '{': + return parseCompoundStatement(node); + + case Token_identifier: + if (parseLabeledStatement(node)) + return true; + break; + } + + return parseExpressionOrDeclarationStatement(node); +} + +bool Parser::parseExpressionOrDeclarationStatement(StatementAST *&node) +{ + bool blocked = block_errors(true); + + std::size_t start = token_stream.cursor(); + + StatementAST *decl_ast = 0; + bool maybe_amb = parseDeclarationStatement(decl_ast); + maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';'; + + std::size_t end = token_stream.cursor(); + + token_stream.rewind((int) start); + StatementAST *expr_ast = 0; + maybe_amb &= parseExpressionStatement(expr_ast); + maybe_amb &= token_stream.kind(token_stream.cursor() - 1) == ';'; + + if (maybe_amb) { + Q_ASSERT(decl_ast && expr_ast); + ExpressionOrDeclarationStatementAST *ast = + CreateNode<ExpressionOrDeclarationStatementAST>(_M_pool); + ast->declaration = decl_ast; + ast->expression = expr_ast; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } else { + token_stream.rewind((int) std::max(end, token_stream.cursor())); + + node = decl_ast; + if (!node) + node = expr_ast; + } + + block_errors(blocked); + + if (!node) + syntaxError(); + + return node != 0; +} + +bool Parser::parseCondition(ConditionAST *&node, bool initRequired) +{ + std::size_t start = token_stream.cursor(); + + ConditionAST *ast = CreateNode<ConditionAST>(_M_pool); + TypeSpecifierAST *spec = 0; + + if (parseTypeSpecifier(spec)) { + ast->type_specifier = spec; + + std::size_t declarator_start = token_stream.cursor(); + + DeclaratorAST *decl = 0; + if (!parseDeclarator(decl)) { + token_stream.rewind((int) declarator_start); + if (!initRequired && !parseAbstractDeclarator(decl)) + decl = 0; + } + + if (decl && (!initRequired || token_stream.lookAhead() == '=')) { + ast->declarator = decl; + + if (token_stream.lookAhead() == '=') { + token_stream.nextToken(); + + parseExpression(ast->expression); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + + token_stream.rewind((int) start); + + if (!parseCommaExpression(ast->expression)) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + + +bool Parser::parseWhileStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_while, "while"); + ADVANCE('(' , "("); + + ConditionAST *cond = 0; + if (!parseCondition(cond)) { + reportError(QLatin1String("condition expected")); + return false; + } + ADVANCE(')', ")"); + + StatementAST *body = 0; + if (!parseStatement(body)) { + reportError(QLatin1String("statement expected")); + return false; + } + + WhileStatementAST *ast = CreateNode<WhileStatementAST>(_M_pool); + ast->condition = cond; + ast->statement = body; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDoStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_do, "do"); + + StatementAST *body = 0; + if (!parseStatement(body)) { + reportError(QLatin1String("statement expected")); + //return false; + } + + ADVANCE_NR(Token_while, "while"); + ADVANCE_NR('(' , "("); + + ExpressionAST *expr = 0; + if (!parseCommaExpression(expr)) { + reportError(QLatin1String("expression expected")); + //return false; + } + + ADVANCE_NR(')', ")"); + ADVANCE_NR(';', ";"); + + DoStatementAST *ast = CreateNode<DoStatementAST>(_M_pool); + ast->statement = body; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseForStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_for, "for"); + ADVANCE('(', "("); + + StatementAST *init = 0; + if (!parseForInitStatement(init)) { + reportError(QLatin1String("for initialization expected")); + return false; + } + + ConditionAST *cond = 0; + parseCondition(cond); + ADVANCE(';', ";"); + + ExpressionAST *expr = 0; + parseCommaExpression(expr); + ADVANCE(')', ")"); + + StatementAST *body = 0; + if (!parseStatement(body)) + return false; + + ForStatementAST *ast = CreateNode<ForStatementAST>(_M_pool); + ast->init_statement = init; + ast->condition = cond; + ast->expression = expr; + ast->statement = body; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseForInitStatement(StatementAST *&node) +{ + if (parseDeclarationStatement(node)) + return true; + + return parseExpressionStatement(node); +} + +bool Parser::parseCompoundStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK('{'); + + CompoundStatementAST *ast = CreateNode<CompoundStatementAST>(_M_pool); + + while (token_stream.lookAhead()) { + if (token_stream.lookAhead() == '}') + break; + + std::size_t startStmt = token_stream.cursor(); + + StatementAST *stmt = 0; + if (!parseStatement(stmt)) { + if (startStmt == token_stream.cursor()) + token_stream.nextToken(); + + skipUntilStatement(); + } else { + ast->statements = snoc(ast->statements, stmt, _M_pool); + } + } + + ADVANCE_NR('}', "}"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseIfStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + ADVANCE(Token_if, "if"); + + ADVANCE('(' , "("); + + IfStatementAST *ast = CreateNode<IfStatementAST>(_M_pool); + + ConditionAST *cond = 0; + if (!parseCondition(cond)) { + reportError(QLatin1String("condition expected")); + return false; + } + ADVANCE(')', ")"); + + StatementAST *stmt = 0; + if (!parseStatement(stmt)) { + reportError(QLatin1String("statement expected")); + return false; + } + + ast->condition = cond; + ast->statement = stmt; + + if (token_stream.lookAhead() == Token_else) { + token_stream.nextToken(); + + if (!parseStatement(ast->else_statement)) { + reportError(QLatin1String("statement expected")); + return false; + } + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseSwitchStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + ADVANCE(Token_switch, "switch"); + + ADVANCE('(' , "("); + + ConditionAST *cond = 0; + if (!parseCondition(cond)) { + reportError(QLatin1String("condition expected")); + return false; + } + ADVANCE(')', ")"); + + StatementAST *stmt = 0; + if (!parseCompoundStatement(stmt)) { + syntaxError(); + return false; + } + + SwitchStatementAST *ast = CreateNode<SwitchStatementAST>(_M_pool); + ast->condition = cond; + ast->statement = stmt; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseLabeledStatement(StatementAST *&node) +{ + switch (token_stream.lookAhead()) { + case Token_identifier: + case Token_default: + if (token_stream.lookAhead(1) == ':') { + token_stream.nextToken(); + token_stream.nextToken(); + + StatementAST *stmt = 0; + if (parseStatement(stmt)) { + node = stmt; + return true; + } + } + break; + + case Token_case: { + token_stream.nextToken(); + ExpressionAST *expr = 0; + if (!parseConstantExpression(expr)) { + reportError(QLatin1String("expression expected")); + } else if (token_stream.lookAhead() == Token_ellipsis) { + token_stream.nextToken(); + + ExpressionAST *expr2 = 0; + if (!parseConstantExpression(expr2)) + reportError(QLatin1String("expression expected")); + } + ADVANCE(':', ":"); + + StatementAST *stmt = 0; + if (parseStatement(stmt)) { + node = stmt; + return true; + } + } + break; + + } + + return false; +} + +bool Parser::parseBlockDeclaration(DeclarationAST *&node) +{ + switch (token_stream.lookAhead()) { + case Token_typedef: + return parseTypedef(node); + case Token_using: + return parseUsing(node); + case Token_asm: + return parseAsmDefinition(node); + case Token_namespace: + return parseNamespaceAliasDefinition(node); + } + + std::size_t start = token_stream.cursor(); + + const ListNode<std::size_t> *cv = 0; + parseCvQualify(cv); + + const ListNode<std::size_t> *storageSpec = 0; + parseStorageClassSpecifier(storageSpec); + + parseCvQualify(cv); + + TypeSpecifierAST *spec = 0; + if (!parseTypeSpecifierOrClassSpec(spec)) { // replace with simpleTypeSpecifier?!?! + token_stream.rewind((int) start); + return false; + } + + parseCvQualify(cv); + spec->cv = cv; + + const ListNode<InitDeclaratorAST*> *declarators = 0; + parseInitDeclaratorList(declarators); + + if (token_stream.lookAhead() != ';') { + token_stream.rewind((int) start); + return false; + } + token_stream.nextToken(); + + SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool); + ast->type_specifier = spec; + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNamespaceAliasDefinition(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_namespace); + + NamespaceAliasDefinitionAST *ast + = CreateNode<NamespaceAliasDefinitionAST>(_M_pool); + + ADVANCE(Token_identifier, "identifier"); + ast->namespace_name = token_stream.cursor() - 1; + + ADVANCE('=', "="); + + if (!parseName(ast->alias_name)) + reportError(QLatin1String("Namespace name expected")); + + ADVANCE(';', ";"); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDeclarationStatement(StatementAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeclarationAST *decl = 0; + if (!parseBlockDeclaration(decl)) + return false; + + DeclarationStatementAST *ast = CreateNode<DeclarationStatementAST>(_M_pool); + ast->declaration = decl; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDeclarationInternal(DeclarationAST *&node) +{ + std::size_t start = token_stream.cursor(); + + // that is for the case '__declspec(dllexport) int ...' or + // '__declspec(dllexport) inline int ...', etc. + WinDeclSpecAST *winDeclSpec = 0; + parseWinDeclSpec(winDeclSpec); + + const ListNode<std::size_t> *funSpec = 0; + bool hasFunSpec = parseFunctionSpecifier(funSpec); + + const ListNode<std::size_t> *cv = 0; + parseCvQualify(cv); + + const ListNode<std::size_t> *storageSpec = 0; + bool hasStorageSpec = parseStorageClassSpecifier(storageSpec); + + if (hasStorageSpec && !hasFunSpec) + hasFunSpec = parseFunctionSpecifier(funSpec); + + // that is for the case 'friend __declspec(dllexport) ....' + parseWinDeclSpec(winDeclSpec); + + if (!cv) + parseCvQualify(cv); + + int index = (int) token_stream.cursor(); + NameAST *name = 0; + if (parseName(name, true) && token_stream.lookAhead() == '(') { + // no type specifier, maybe a constructor or a cast operator?? + + token_stream.rewind((int) index); + + InitDeclaratorAST *declarator = 0; + if (parseInitDeclarator(declarator)) { + switch (token_stream.lookAhead()) { + case ';': { + token_stream.nextToken(); + + SimpleDeclarationAST *ast + = CreateNode<SimpleDeclarationAST>(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->init_declarators = snoc(ast->init_declarators, + declarator, _M_pool); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case ':': { + CtorInitializerAST *ctorInit = 0; + StatementAST *funBody = 0; + + if (parseCtorInitializer(ctorInit) + && parseFunctionBody(funBody)) { + FunctionDefinitionAST *ast + = CreateNode<FunctionDefinitionAST>(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->init_declarator = declarator; + ast->function_body = funBody; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + break; + + case '{': { + StatementAST *funBody = 0; + if (parseFunctionBody(funBody)) { + FunctionDefinitionAST *ast + = CreateNode<FunctionDefinitionAST>(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->init_declarator = declarator; + ast->function_body = funBody; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + break; + + case '(': + case '[': + // ops!! it seems a declarator + goto start_decl; + break; + } + + } + } + +start_decl: + token_stream.rewind((int) index); + + if (token_stream.lookAhead() == Token_const + && token_stream.lookAhead(1) == Token_identifier + && token_stream.lookAhead(2) == '=') { + // constant definition + token_stream.nextToken(); // skip const + + const ListNode<InitDeclaratorAST*> *declarators = 0; + if (!parseInitDeclaratorList(declarators)) { + syntaxError(); + return false; + } + + ADVANCE(';', ";"); + +#if defined(__GNUC__) +#warning "mark the ast as constant" +#endif + SimpleDeclarationAST *ast = CreateNode<SimpleDeclarationAST>(_M_pool); + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + + TypeSpecifierAST *spec = 0; + if (parseTypeSpecifier(spec)) { + Q_ASSERT(spec); + + if (!hasFunSpec) + parseFunctionSpecifier(funSpec); // e.g. "void inline" + + spec->cv = cv; + + const ListNode<InitDeclaratorAST*> *declarators = 0; + InitDeclaratorAST *decl = 0; + int startDeclarator = (int) token_stream.cursor(); + bool maybeFunctionDefinition = false; + + if (token_stream.lookAhead() != ';') { + if (parseInitDeclarator(decl) && token_stream.lookAhead() == '{') { + // function definition + maybeFunctionDefinition = true; + } else { + token_stream.rewind((int) startDeclarator); + if (!parseInitDeclaratorList(declarators)) { + syntaxError(); + return false; + } + } + } + + switch (token_stream.lookAhead()) { + case ';': { + token_stream.nextToken(); + SimpleDeclarationAST *ast + = CreateNode<SimpleDeclarationAST>(_M_pool); + + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->type_specifier = spec; + ast->win_decl_specifiers = winDeclSpec; + ast->init_declarators = declarators; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case '{': { + if (!maybeFunctionDefinition) { + syntaxError(); + return false; + } + + StatementAST *funBody = 0; + if (parseFunctionBody(funBody)) { + FunctionDefinitionAST *ast + = CreateNode<FunctionDefinitionAST>(_M_pool); + + ast->win_decl_specifiers = winDeclSpec; + ast->storage_specifiers = storageSpec; + ast->function_specifiers = funSpec; + ast->type_specifier = spec; + ast->init_declarator = decl; + ast->function_body = funBody; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + break; + } // end switch + } + + syntaxError(); + return false; +} + +bool Parser::skipFunctionBody(StatementAST *&) +{ +#if defined(__GNUC__) +#warning "Parser::skipFunctionBody() -- implement me" +#endif + Q_ASSERT(0); // ### not implemented + return 0; +} + +bool Parser::parseFunctionBody(StatementAST *&node) +{ + if (control->skipFunctionBody()) + return skipFunctionBody(node); + + return parseCompoundStatement(node); +} + +bool Parser::parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node) +{ + if (parseClassSpecifier(node)) + return true; + else if (parseEnumSpecifier(node)) + return true; + else if (parseTypeSpecifier(node)) + return true; + + return false; +} + +bool Parser::parseTryBlockStatement(StatementAST *&node) +{ +#if defined(__GNUC__) +#warning "implement me" +#endif + CHECK(Token_try); + + StatementAST *stmt = 0; + if (!parseCompoundStatement(stmt)) { + syntaxError(); + return false; + } + + if (token_stream.lookAhead() != Token_catch) { + reportError(QLatin1String("catch expected")); + return false; + } + + while (token_stream.lookAhead() == Token_catch) { + token_stream.nextToken(); + ADVANCE('(', "("); + ConditionAST *cond = 0; + if (token_stream.lookAhead() == Token_ellipsis) { + token_stream.nextToken(); + } else if (!parseCondition(cond, false)) { + reportError(QLatin1String("condition expected")); + return false; + } + ADVANCE(')', ")"); + + StatementAST *body = 0; + if (!parseCompoundStatement(body)) { + syntaxError(); + return false; + } + } + + node = stmt; + return true; +} + +bool Parser::parsePrimaryExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + PrimaryExpressionAST *ast = CreateNode<PrimaryExpressionAST>(_M_pool); + + switch (token_stream.lookAhead()) { + case Token_string_literal: + parseStringLiteral(ast->literal); + break; + + case Token_number_literal: + case Token_char_literal: + case Token_true: + case Token_false: + case Token_this: + ast->token = token_stream.cursor(); + token_stream.nextToken(); + break; + + case '(': + token_stream.nextToken(); + + if (token_stream.lookAhead() == '{') { + if (!parseCompoundStatement(ast->expression_statement)) + return false; + } else { + if (!parseExpression(ast->sub_expression)) + return false; + } + + CHECK(')'); + break; + + default: + if (!parseName(ast->name)) + return false; + + break; + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + + +/* + postfix-expression-internal: + [ expression ] + ( expression-list [opt] ) + (.|->) template [opt] id-expression + (.|->) pseudo-destructor-name + ++ + -- +*/ +bool Parser::parsePostfixExpressionInternal(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case '[': { + token_stream.nextToken(); + ExpressionAST *expr = 0; + parseExpression(expr); + CHECK(']'); + + SubscriptExpressionAST *ast + = CreateNode<SubscriptExpressionAST>(_M_pool); + + ast->subscript = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case '(': { + token_stream.nextToken(); + ExpressionAST *expr = 0; + parseExpression(expr); + CHECK(')'); + + FunctionCallAST *ast = CreateNode<FunctionCallAST>(_M_pool); + ast->arguments = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case '.': + case Token_arrow: { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + std::size_t templ = 0; + if (token_stream.lookAhead() == Token_template) { + templ = token_stream.cursor(); + token_stream.nextToken(); + } + + int saved = int(token_stream.cursor()); + NameAST *name = 0; + + if (parseName(name, true) && name->unqualified_name + && name->unqualified_name->template_arguments + && token_stream.lookAhead() == '(') { + // a template method call + // ### reverse the logic + } else { + token_stream.rewind(saved); + name = 0; + + if (!parseName(name, templ != 0)) + return false; + } + + ClassMemberAccessAST *ast = CreateNode<ClassMemberAccessAST>(_M_pool); + ast->op = op; + ast->name = name; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case Token_incr: + case Token_decr: { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + IncrDecrExpressionAST *ast = CreateNode<IncrDecrExpressionAST>(_M_pool); + ast->op = op; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + default: + return false; + } +} + +/* + postfix-expression: + simple-type-specifier ( expression-list [opt] ) + primary-expression postfix-expression-internal* +*/ +bool Parser::parsePostfixExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case Token_dynamic_cast: + case Token_static_cast: + case Token_reinterpret_cast: + case Token_const_cast: { + std::size_t castOp = token_stream.cursor(); + token_stream.nextToken(); + + CHECK('<'); + TypeIdAST *typeId = 0; + parseTypeId(typeId); + CHECK('>'); + + CHECK('('); + ExpressionAST *expr = 0; + parseCommaExpression(expr); + CHECK(')'); + + CppCastExpressionAST *ast = CreateNode<CppCastExpressionAST>(_M_pool); + ast->op = castOp; + ast->type_id = typeId; + ast->expression = expr; + + ExpressionAST *e = 0; + while (parsePostfixExpressionInternal(e)) + ast->sub_expressions = snoc(ast->sub_expressions, e, _M_pool); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case Token_typename: { + std::size_t token = token_stream.cursor(); + token_stream.nextToken(); + + NameAST* name = 0; + if (!parseName(name, true)) + return false; + + CHECK('('); + ExpressionAST *expr = 0; + parseCommaExpression(expr); + CHECK(')'); + + TypeIdentificationAST *ast = CreateNode<TypeIdentificationAST>(_M_pool); + ast->typename_token = token; + ast->name = name; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case Token_typeid: { + token_stream.nextToken(); + + CHECK('('); + TypeIdAST *typeId = 0; + parseTypeId(typeId); + CHECK(')'); + + TypeIdentificationAST *ast = CreateNode<TypeIdentificationAST>(_M_pool); + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + default: + break; + } + + std::size_t saved_pos = token_stream.cursor(); + + TypeSpecifierAST *typeSpec = 0; + ExpressionAST *expr = 0; + + // let's try to parse a type + NameAST *name = 0; + if (parseName(name, true)) { + Q_ASSERT(name->unqualified_name); + + bool has_template_args = name->unqualified_name->template_arguments != 0; + + if (has_template_args && token_stream.lookAhead() == '(') { + ExpressionAST *cast_expr = 0; + if (parseCastExpression(cast_expr) + && cast_expr->kind == AST::Kind_CastExpression) { + token_stream.rewind((int) saved_pos); + parsePrimaryExpression(expr); + goto L_no_rewind; + } + } + } + + token_stream.rewind((int) saved_pos); + +L_no_rewind: + if (!expr && parseSimpleTypeSpecifier(typeSpec) + && token_stream.lookAhead() == '(') { + token_stream.nextToken(); // skip '(' + parseCommaExpression(expr); + CHECK(')'); + } else if (expr) { + typeSpec = 0; + } else { + typeSpec = 0; + token_stream.rewind((int) start); + + if (!parsePrimaryExpression(expr)) + return false; + } + + const ListNode<ExpressionAST*> *sub_expressions = 0; + ExpressionAST *sub_expression = 0; + + while (parsePostfixExpressionInternal(sub_expression)) + sub_expressions = snoc(sub_expressions, sub_expression, _M_pool); + + if (sub_expressions || !expr || (typeSpec && expr)) { + PostfixExpressionAST *ast = CreateNode<PostfixExpressionAST>(_M_pool); + ast->type_specifier = typeSpec; + ast->expression = expr; + ast->sub_expressions = sub_expressions; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } else + node = expr; + + return true; +} + +bool Parser::parseUnaryExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + switch (token_stream.lookAhead()) { + case Token_incr: + case Token_decr: + case '*': + case '&': + case '+': + case '-': + case '!': + case '~': { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *expr = 0; + if (!parseCastExpression(expr)) + return false; + + UnaryExpressionAST *ast = CreateNode<UnaryExpressionAST>(_M_pool); + ast->op = op; + ast->expression = expr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + return true; + + case Token_sizeof: { + std::size_t sizeof_token = token_stream.cursor(); + token_stream.nextToken(); + + SizeofExpressionAST *ast = CreateNode<SizeofExpressionAST>(_M_pool); + ast->sizeof_token = sizeof_token; + + std::size_t index = token_stream.cursor(); + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + if (parseTypeId(ast->type_id) && token_stream.lookAhead() == ')') { + token_stream.nextToken(); // skip ) + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; + } + + ast->type_id = 0; + token_stream.rewind((int) index); + } + + if (!parseUnaryExpression(ast->expression)) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + return true; + } + + default: + break; + } + + int token = token_stream.lookAhead(); + + if (token == Token_new + || (token == Token_scope && token_stream.lookAhead(1) == Token_new)) + return parseNewExpression(node); + + if (token == Token_delete + || (token == Token_scope && token_stream.lookAhead(1) == Token_delete)) + return parseDeleteExpression(node); + + return parsePostfixExpression(node); +} + +bool Parser::parseNewExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + NewExpressionAST *ast = CreateNode<NewExpressionAST>(_M_pool); + + if (token_stream.lookAhead() == Token_scope + && token_stream.lookAhead(1) == Token_new) { + ast->scope_token = token_stream.cursor(); + token_stream.nextToken(); + } + + CHECK(Token_new); + ast->new_token = token_stream.cursor() - 1; + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + parseCommaExpression(ast->expression); + CHECK(')'); + } + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + parseTypeId(ast->type_id); + CHECK(')'); + } else { + parseNewTypeId(ast->new_type_id); + } + + parseNewInitializer(ast->new_initializer); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNewTypeId(NewTypeIdAST *&node) +{ + std::size_t start = token_stream.cursor(); + + TypeSpecifierAST *typeSpec = 0; + if (!parseTypeSpecifier(typeSpec)) + return false; + + NewTypeIdAST *ast = CreateNode<NewTypeIdAST>(_M_pool); + ast->type_specifier = typeSpec; + + parseNewDeclarator(ast->new_declarator); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNewDeclarator(NewDeclaratorAST *&node) +{ + std::size_t start = token_stream.cursor(); + + NewDeclaratorAST *ast = CreateNode<NewDeclaratorAST>(_M_pool); + + PtrOperatorAST *ptrOp = 0; + if (parsePtrOperator(ptrOp)) { + ast->ptr_op = ptrOp; + parseNewDeclarator(ast->sub_declarator); + } + + while (token_stream.lookAhead() == '[') { + token_stream.nextToken(); + ExpressionAST *expr = 0; + parseExpression(expr); + ast->expressions = snoc(ast->expressions, expr, _M_pool); + ADVANCE(']', "]"); + } + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseNewInitializer(NewInitializerAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK('('); + + NewInitializerAST *ast = CreateNode<NewInitializerAST>(_M_pool); + + parseCommaExpression(ast->expression); + + CHECK(')'); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseDeleteExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + DeleteExpressionAST *ast = CreateNode<DeleteExpressionAST>(_M_pool); + + if (token_stream.lookAhead() == Token_scope + && token_stream.lookAhead(1) == Token_delete) { + ast->scope_token = token_stream.cursor(); + token_stream.nextToken(); + } + + CHECK(Token_delete); + ast->delete_token = token_stream.cursor() - 1; + + if (token_stream.lookAhead() == '[') { + ast->lbracket_token = token_stream.cursor(); + token_stream.nextToken(); + CHECK(']'); + ast->rbracket_token = token_stream.cursor() - 1; + } + + if (!parseCastExpression(ast->expression)) + return false; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseCastExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() == '(') { + token_stream.nextToken(); + + CastExpressionAST *ast = CreateNode<CastExpressionAST>(_M_pool); + + if (parseTypeId(ast->type_id)) { + if (token_stream.lookAhead() == ')') { + token_stream.nextToken(); + + if (parseCastExpression(ast->expression)) { + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; + } + } + } + } + + token_stream.rewind((int) start); + return parseUnaryExpression(node); +} + +bool Parser::parsePmExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseCastExpression(node) || !node) // ### fixme + return false; + + while (token_stream.lookAhead() == Token_ptrmem) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseCastExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseMultiplicativeExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parsePmExpression(node)) + return false; + + while (token_stream.lookAhead() == '*' + || token_stream.lookAhead() == '/' + || token_stream.lookAhead() == '%') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parsePmExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + + +bool Parser::parseAdditiveExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseMultiplicativeExpression(node)) + return false; + + while (token_stream.lookAhead() == '+' || token_stream.lookAhead() == '-') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseMultiplicativeExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseShiftExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseAdditiveExpression(node)) + return false; + + while (token_stream.lookAhead() == Token_shift) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseAdditiveExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseRelationalExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseShiftExpression(node)) + return false; + + while (token_stream.lookAhead() == '<' + || (token_stream.lookAhead() == '>' && !templArgs) + || token_stream.lookAhead() == Token_leq + || token_stream.lookAhead() == Token_geq) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseShiftExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseEqualityExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseRelationalExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == Token_eq + || token_stream.lookAhead() == Token_not_eq) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseRelationalExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseAndExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseEqualityExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == '&') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseEqualityExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseExclusiveOrExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseAndExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == '^') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseAndExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseInclusiveOrExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseExclusiveOrExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == '|') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseExclusiveOrExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseLogicalAndExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseInclusiveOrExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == Token_and) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseInclusiveOrExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseLogicalOrExpression(ExpressionAST *&node, bool templArgs) +{ + std::size_t start = token_stream.cursor(); + + if (!parseLogicalAndExpression(node, templArgs)) + return false; + + while (token_stream.lookAhead() == Token_or) { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseLogicalAndExpression(rightExpr, templArgs)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseConditionalExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseLogicalOrExpression(node)) + return false; + + if (token_stream.lookAhead() == '?') { + token_stream.nextToken(); + + ExpressionAST *leftExpr = 0; + if (!parseExpression(leftExpr)) + return false; + + CHECK(':'); + + ExpressionAST *rightExpr = 0; + if (!parseAssignmentExpression(rightExpr)) + return false; + + ConditionalExpressionAST *ast + = CreateNode<ConditionalExpressionAST>(_M_pool); + + ast->condition = node; + ast->left_expression = leftExpr; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseAssignmentExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (token_stream.lookAhead() == Token_throw && !parseThrowExpression(node)) + return false; + else if (!parseConditionalExpression(node)) + return false; + + while (token_stream.lookAhead() == Token_assign + || token_stream.lookAhead() == '=') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseConditionalExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseConstantExpression(ExpressionAST *&node) +{ + return parseConditionalExpression(node); +} + +bool Parser::parseExpression(ExpressionAST *&node) +{ + return parseCommaExpression(node); +} + +bool Parser::parseCommaExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + if (!parseAssignmentExpression(node)) + return false; + + while (token_stream.lookAhead() == ',') { + std::size_t op = token_stream.cursor(); + token_stream.nextToken(); + + ExpressionAST *rightExpr = 0; + if (!parseAssignmentExpression(rightExpr)) + return false; + + BinaryExpressionAST *ast = CreateNode<BinaryExpressionAST>(_M_pool); + ast->op = op; + ast->left_expression = node; + ast->right_expression = rightExpr; + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + } + + return true; +} + +bool Parser::parseThrowExpression(ExpressionAST *&node) +{ + std::size_t start = token_stream.cursor(); + + CHECK(Token_throw); + + ThrowExpressionAST *ast = CreateNode<ThrowExpressionAST>(_M_pool); + ast->throw_token = token_stream.cursor() - 1; + + parseAssignmentExpression(ast->expression); + + UPDATE_POS(ast, start, token_stream.cursor()); + node = ast; + + return true; +} + +bool Parser::parseQ_ENUMS(DeclarationAST *&node) +{ + + if ((token_stream.lookAhead() != Token_Q_ENUMS) && + (token_stream.lookAhead() != Token_Q_ENUM)) + return false; + + if (token_stream.lookAhead(1) != '(') + return false; + + token_stream.nextToken(); + token_stream.nextToken(); + + int firstToken = token_stream.cursor(); + while (token_stream.lookAhead() != ')') + token_stream.nextToken(); + + QEnumsAST *ast = CreateNode<QEnumsAST>(_M_pool); + UPDATE_POS(ast, firstToken, token_stream.cursor()); + node = ast; + + token_stream.nextToken(); + + return true; +} + +bool Parser::parseQ_PROPERTY(DeclarationAST *&node) +{ + if (token_stream.lookAhead() != Token_Q_PROPERTY) + return false; + + if (token_stream.lookAhead(1) != '(') + return false; + + token_stream.nextToken(); + token_stream.nextToken(); + + int firstToken = token_stream.cursor(); + while (token_stream.lookAhead() != ')') + token_stream.nextToken(); + + QPropertyAST *ast = CreateNode<QPropertyAST>(_M_pool); + UPDATE_POS(ast, firstToken, token_stream.cursor()); + node = ast; + +// const Token &t1 = token_stream[firstToken]; +// const Token &t2 = token_stream[token_stream.cursor()]; +// printf("property: %s\n", +// qPrintable(QString::fromLatin1(t1.text + t1.position, t2.position - t1.position))); + + token_stream.nextToken(); + + return true; +} + +bool Parser::block_errors(bool block) +{ + bool current = _M_block_errors; + _M_block_errors = block; + return current; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/sources/shiboken2/ApiExtractor/parser/parser.h b/sources/shiboken2/ApiExtractor/parser/parser.h new file mode 100644 index 000000000..7aa5b9ad7 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/parser.h @@ -0,0 +1,204 @@ +/**************************************************************************** +** +** 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 PARSER_H +#define PARSER_H + +#include "ast.h" +#include "lexer.h" + +#include <QtCore/QString> + +class FileSymbol; +class Control; + +class Parser +{ +public: + Parser(Control *control); + ~Parser(); + + LocationManager &location() { return _M_location; } + + TranslationUnitAST *parse(const char *contents, std::size_t size, pool *p); + +private: + void reportError(const QString& msg); + void syntaxError(); + void tokenRequiredError(int expected); + +public: + bool skipFunctionBody(StatementAST *&node); + +public: + bool parse_Attribute__(); + bool parseAbstractDeclarator(DeclaratorAST *&node); + bool parseAccessSpecifier(DeclarationAST *&node); + bool parseAdditiveExpression(ExpressionAST *&node); + bool parseAndExpression(ExpressionAST *&node, bool templArgs = false); + bool parseAsmDefinition(DeclarationAST *&node); + bool parseAssignmentExpression(ExpressionAST *&node); + bool parseBaseClause(BaseClauseAST *&node); + bool parseBaseSpecifier(BaseSpecifierAST *&node); + bool parseBlockDeclaration(DeclarationAST *&node); + bool parseCastExpression(ExpressionAST *&node); + bool parseClassSpecifier(TypeSpecifierAST *&node); + bool parseForwardDeclarationSpecifier(TypeSpecifierAST *&node); + bool parseCommaExpression(ExpressionAST *&node); + bool parseCompoundStatement(StatementAST *&node); + bool parseCondition(ConditionAST *&node, bool initRequired = true); + bool parseConditionalExpression(ExpressionAST *&node); + bool parseConstantExpression(ExpressionAST *&node); + bool parseCtorInitializer(CtorInitializerAST *&node); + bool parseCvQualify(const ListNode<std::size_t> *&node); + bool parseDeclaration(DeclarationAST *&node); + bool parseDeclarationInternal(DeclarationAST *&node); + bool parseDeclarationStatement(StatementAST *&node); + bool parseDeclarator(DeclaratorAST *&node); + bool parseDeleteExpression(ExpressionAST *&node); + bool parseDoStatement(StatementAST *&node); + bool parseElaboratedTypeSpecifier(TypeSpecifierAST *&node); + bool parseEnumSpecifier(TypeSpecifierAST *&node); + bool parseEnumerator(EnumeratorAST *&node); + bool parseEqualityExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseExceptionSpecification(ExceptionSpecificationAST *&node); + bool parseExclusiveOrExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseExpression(ExpressionAST *&node); + bool parseExpressionOrDeclarationStatement(StatementAST *&node); + bool parseExpressionStatement(StatementAST *&node); + bool parseForInitStatement(StatementAST *&node); + bool parseForStatement(StatementAST *&node); + bool parseFunctionBody(StatementAST *&node); + bool parseFunctionSpecifier(const ListNode<std::size_t> *&node); + bool parseIfStatement(StatementAST *&node); + bool parseInclusiveOrExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseInitDeclarator(InitDeclaratorAST *&node); + bool parseInitDeclaratorList(const ListNode<InitDeclaratorAST*> *&node); + bool parseInitializer(InitializerAST *&node); + bool parseInitializerClause(InitializerClauseAST *&node); + bool parseLabeledStatement(StatementAST *&node); + bool parseLinkageBody(LinkageBodyAST *&node); + bool parseLinkageSpecification(DeclarationAST *&node); + bool parseLogicalAndExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseLogicalOrExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseMemInitializer(MemInitializerAST *&node); + bool parseMemInitializerList(const ListNode<MemInitializerAST*> *&node); + bool parseMemberSpecification(DeclarationAST *&node); + bool parseMultiplicativeExpression(ExpressionAST *&node); + bool parseName(NameAST *&node, bool acceptTemplateId = false); + bool parseNamespace(DeclarationAST *&node); + bool parseNamespaceAliasDefinition(DeclarationAST *&node); + bool parseNewDeclarator(NewDeclaratorAST *&node); + bool parseNewExpression(ExpressionAST *&node); + bool parseNewInitializer(NewInitializerAST *&node); + bool parseNewTypeId(NewTypeIdAST *&node); + bool parseNoExcept(); + bool parseOperator(OperatorAST *&node); + bool parseOperatorFunctionId(OperatorFunctionIdAST *&node); + bool parseParameterDeclaration(ParameterDeclarationAST *&node); + bool parseParameterDeclarationClause(ParameterDeclarationClauseAST *&node); + bool parseParameterDeclarationList(const ListNode<ParameterDeclarationAST*> *&node); + bool parsePmExpression(ExpressionAST *&node); + bool parsePostfixExpression(ExpressionAST *&node); + bool parsePostfixExpressionInternal(ExpressionAST *&node); + bool parsePrimaryExpression(ExpressionAST *&node); + bool parsePtrOperator(PtrOperatorAST *&node); + bool parsePtrToMember(PtrToMemberAST *&node); + bool parseRelationalExpression(ExpressionAST *&node, + bool templArgs = false); + bool parseShiftExpression(ExpressionAST *&node); + bool parseSimpleTypeSpecifier(TypeSpecifierAST *&node, + bool onlyIntegral = false); + bool parseStatement(StatementAST *&node); + bool parseStorageClassSpecifier(const ListNode<std::size_t> *&node); + bool parseStringLiteral(StringLiteralAST *&node); + bool parseSwitchStatement(StatementAST *&node); + bool parseTemplateArgument(TemplateArgumentAST *&node); + bool parseTemplateArgumentList(const ListNode<TemplateArgumentAST*> *&node, + bool reportError = true); + bool parseTemplateDeclaration(DeclarationAST *&node); + bool parseTemplateParameter(TemplateParameterAST *&node); + bool parseTemplateParameterList(const ListNode<TemplateParameterAST*> *&node); + bool parseThrowExpression(ExpressionAST *&node); + bool parseTranslationUnit(TranslationUnitAST *&node); + bool parseTryBlockStatement(StatementAST *&node); + bool parseTypeId(TypeIdAST *&node); + bool parseTypeIdList(const ListNode<TypeIdAST*> *&node); + bool parseTypeParameter(TypeParameterAST *&node); + bool parseTypeSpecifier(TypeSpecifierAST *&node); + bool parseTypeSpecifierOrClassSpec(TypeSpecifierAST *&node); + bool parseTypedef(DeclarationAST *&node); + bool parseUnaryExpression(ExpressionAST *&node); + bool parseUnqualifiedName(UnqualifiedNameAST *&node, + bool parseTemplateId = true); + bool parseUsing(DeclarationAST *&node); + bool parseUsingDirective(DeclarationAST *&node); + bool parseWhileStatement(StatementAST *&node); + bool parseWinDeclSpec(WinDeclSpecAST *&node); + + bool parseQ_PROPERTY(DeclarationAST *&node); + bool parseQ_ENUMS(DeclarationAST *&node); + + bool skipUntil(int token); + bool skipUntilDeclaration(); + bool skipUntilStatement(); + bool skip(int l, int r); + + void advance(); + + // private: + TokenStream token_stream; + LocationTable location_table; + LocationTable line_table; + + bool block_errors(bool block); + +private: + QString tokenText(AST *) const; + + LocationManager _M_location; + Control *control; + Lexer lexer; + pool *_M_pool; + bool _M_block_errors; + +private: + Parser(const Parser& source); + void operator = (const Parser& source); +}; + +#endif + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/r++.macros b/sources/shiboken2/ApiExtractor/parser/r++.macros new file mode 100644 index 000000000..455276c84 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/r++.macros @@ -0,0 +1,28 @@ + +#define __attribute__(a...) +#define __typeof__ __typeof + +#define __extension +#define __extension__ + +#define __restrict +#define __restrict__ + +#define __volatile volatile +#define __volatile__ volatile + +#define __inline inline +#define __inline__ inline + +#define __const const +#define __const__ const + +#define __asm asm +#define __asm__ asm + +#define __GNUC__ 3 +//#define __GNUC_MINOR__ 4 + +#define __ROBC__ 0 +#define __ROBC_MINOR__ 1 + diff --git a/sources/shiboken2/ApiExtractor/parser/rpp-allocator.h b/sources/shiboken2/ApiExtractor/parser/rpp-allocator.h new file mode 100644 index 000000000..4331ef7d4 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp-allocator.h @@ -0,0 +1,29 @@ +/**************************************************************************** +** +** 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 "parser/rxx_allocator.h" diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/builtin-macros.cpp b/sources/shiboken2/ApiExtractor/parser/rpp/builtin-macros.cpp new file mode 100644 index 000000000..ccc150339 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/builtin-macros.cpp @@ -0,0 +1,28 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-cctype.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-cctype.h new file mode 100644 index 000000000..d2e16b994 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-cctype.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** 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 PP_CCTYPE_H +#define PP_CCTYPE_H + +#include <cctype> + +namespace rpp +{ + +inline bool pp_isalpha(int __ch) +{ + return std::isalpha((unsigned char) __ch) != 0; +} + +inline bool pp_isalnum(int __ch) +{ + return std::isalnum((unsigned char) __ch) != 0; +} + +inline bool pp_isdigit(int __ch) +{ + return std::isdigit((unsigned char) __ch) != 0; +} + +inline bool pp_isspace(int __ch) +{ + return std::isspace((unsigned char) __ch) != 0; +} + +} // namespace rpp + +#endif // PP_CCTYPE_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-configuration b/sources/shiboken2/ApiExtractor/parser/rpp/pp-configuration new file mode 100644 index 000000000..15586dd88 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-configuration @@ -0,0 +1,86 @@ +#define __DBL_MIN_EXP__ (-1021) +#define __FLT_MIN__ 1.17549435e-38F +#define __CHAR_BIT__ 8 +#define __WCHAR_MAX__ 2147483647 +#define __DBL_DENORM_MIN__ 4.9406564584124654e-324 +#define __FLT_EVAL_METHOD__ 2 +#define __DBL_MIN_10_EXP__ (-307) +#define __FINITE_MATH_ONLY__ 0 +#define __GNUC_PATCHLEVEL__ 2 +#define __SHRT_MAX__ 32767 +#define __LDBL_MAX__ 1.18973149535723176502e+4932L +#define __UINTMAX_TYPE__ long long unsigned int +#define __linux 1 +#define __unix 1 +#define __LDBL_MAX_EXP__ 16384 +#define __linux__ 1 +#define __SCHAR_MAX__ 127 +#define __USER_LABEL_PREFIX__ +#define __STDC_HOSTED__ 1 +#define __LDBL_HAS_INFINITY__ 1 +#define __DBL_DIG__ 15 +#define __FLT_EPSILON__ 1.19209290e-7F +#define __GXX_WEAK__ 1 +#define __LDBL_MIN__ 3.36210314311209350626e-4932L +#define __unix__ 1 +#define __DECIMAL_DIG__ 21 +#define __gnu_linux__ 1 +#define __LDBL_HAS_QUIET_NAN__ 1 +#define __GNUC__ 4 +#define __DBL_MAX__ 1.7976931348623157e+308 +#define __DBL_HAS_INFINITY__ 1 +#define __cplusplus 1 +#define __DEPRECATED 1 +#define __DBL_MAX_EXP__ 1024 +#define __GNUG__ 4 +#define __LONG_LONG_MAX__ 9223372036854775807LL +#define __GXX_ABI_VERSION 1002 +#define __FLT_MIN_EXP__ (-125) +#define __DBL_MIN__ 2.2250738585072014e-308 +#define __FLT_MIN_10_EXP__ (-37) +#define __DBL_HAS_QUIET_NAN__ 1 +#define __REGISTER_PREFIX__ +#define __NO_INLINE__ 1 +#define __i386 1 +#define __FLT_MANT_DIG__ 24 +#define __VERSION__ "4.0.2 20050808 (prerelease) (Ubuntu 4.0.1-4ubuntu9)" +#define i386 1 +#define __i486__ 1 +#define unix 1 +#define __i386__ 1 +#define __SIZE_TYPE__ unsigned int +#define __ELF__ 1 +#define __FLT_RADIX__ 2 +#define __LDBL_EPSILON__ 1.08420217248550443401e-19L +#define __FLT_HAS_QUIET_NAN__ 1 +#define __FLT_MAX_10_EXP__ 38 +#define __LONG_MAX__ 2147483647L +#define __FLT_HAS_INFINITY__ 1 +#define linux 1 +#define __EXCEPTIONS 1 +#define __LDBL_MANT_DIG__ 64 +#define __WCHAR_TYPE__ int +#define __FLT_DIG__ 6 +#define __INT_MAX__ 2147483647 +#define __i486 1 +#define __FLT_MAX_EXP__ 128 +#define __DBL_MANT_DIG__ 53 +#define __WINT_TYPE__ unsigned int +#define __LDBL_MIN_EXP__ (-16381) +#define __LDBL_MAX_10_EXP__ 4932 +#define __DBL_EPSILON__ 2.2204460492503131e-16 +#define __tune_i486__ 1 +#define __INTMAX_MAX__ 9223372036854775807LL +#define __FLT_DENORM_MIN__ 1.40129846e-45F +#define __FLT_MAX__ 3.40282347e+38F +#define __INTMAX_TYPE__ long long int +#define __GNUC_MINOR__ 0 +#define __DBL_MAX_10_EXP__ 308 +#define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L +#define __PTRDIFF_TYPE__ int +#define __LDBL_MIN_10_EXP__ (-4931) +#define __LDBL_DIG__ 18 +#define _GNU_SOURCE 1 + + +#define __STDC__ diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-engine-bits.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-engine-bits.h new file mode 100644 index 000000000..3d8aee029 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-engine-bits.h @@ -0,0 +1,1300 @@ +/**************************************************************************** +** +** 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 PP_ENGINE_BITS_H +#define PP_ENGINE_BITS_H + +#include "pp.h" +#include <sys/stat.h> +#include <cstdio> +#include <iostream> + +namespace rpp +{ + +inline std::string pp::fix_file_path(std::string const &filename) const +{ +#if defined (PP_OS_WIN) + std::string s = filename; + for (std::string::iterator it = s.begin(); it != s.end(); ++it) { + if (*it == '/') + *it = '\\'; + } + return s; +#else + return filename; +#endif +} + +inline bool pp::is_absolute(std::string const &filename) const +{ +#if defined(PP_OS_WIN) + return filename.length() >= 3 + && filename.at(1) == ':' + && (filename.at(2) == '\\' || filename.at(2) == '/'); +#else + return filename.length() >= 1 + && filename.at(0) == '/'; +#endif +} + +template <typename _OutputIterator> +void pp::file(std::string const &filename, _OutputIterator __result) +{ + FILE *fp = std::fopen(filename.c_str(), "rb"); + if (fp != 0) { + std::string was = env.current_file; + env.current_file = filename; + file(fp, __result); + env.current_file = was; + } + //else + //std::cerr << "** WARNING file ``" << filename << " not found!" << std::endl; +} + +template <typename _OutputIterator> +void pp::file(FILE *fp, _OutputIterator __result) +{ + assert(fp != 0); + +#if defined (HAVE_MMAP) + struct stat st; + fstat(FILENO(fp), &st); + std::size_t size = st.st_size; + char *buffer = 0; + buffer = (char *) ::mmap(0, size, PROT_READ, MAP_SHARED, FILENO(fp), 0); + fclose(fp); + if (!buffer || buffer == (char*) - 1) + return; + this->operator()(buffer, buffer + size, __result); + ::munmap(buffer, size); +#else + std::string buffer; + while (!feof(fp)) { + char tmp[1024]; + int read = (int) fread(tmp, sizeof(char), 1023, fp); + tmp[read] = '\0'; + buffer += tmp; + } + fclose(fp); + this->operator()(buffer.c_str(), buffer.c_str() + buffer.size(), __result); +#endif +} + +template <typename _InputIterator> +bool pp::find_header_protection(_InputIterator __first, _InputIterator __last, std::string *__prot) +{ + int was = env.current_line; + + while (__first != __last) { + if (pp_isspace(*__first)) { + if (*__first == '\n') + ++env.current_line; + + ++__first; + } else if (_PP_internal::comment_p(__first, __last)) { + __first = skip_comment_or_divop(__first, __last); + env.current_line += skip_comment_or_divop.lines; + } else if (*__first == '#') { + __first = skip_blanks(++__first, __last); + env.current_line += skip_blanks.lines; + + if (__first != __last && *__first == 'i') { + _InputIterator __begin = __first; + __first = skip_identifier(__begin, __last); + env.current_line += skip_identifier.lines; + + std::string __directive(__begin, __first); + + if (__directive == "ifndef") { + __first = skip_blanks(__first, __last); + env.current_line += skip_blanks.lines; + + __begin = __first; + __first = skip_identifier(__first, __last); + env.current_line += skip_identifier.lines; + + if (__begin != __first && __first != __last) { + __prot->assign(__begin, __first); + return true; + } + } + } + break; + } else + break; + } + + env.current_line = was; + return false; +} + +inline pp::PP_DIRECTIVE_TYPE pp::find_directive(char const *__directive, std::size_t __size) const +{ + switch (__size) { + case 0: + return PP_UNNAMED_DIRECTIVE; + case 2: + if (__directive[0] == 'i' + && __directive[1] == 'f') + return PP_IF; + break; + + case 4: + if (__directive[0] == 'e' && !strcmp(__directive, "elif")) + return PP_ELIF; + else if (__directive[0] == 'e' && !strcmp(__directive, "else")) + return PP_ELSE; + break; + + case 5: + if (__directive[0] == 'i' && !strcmp(__directive, "ifdef")) + return PP_IFDEF; + else if (__directive[0] == 'u' && !strcmp(__directive, "undef")) + return PP_UNDEF; + else if (__directive[0] == 'e') { + if (!strcmp(__directive, "endif")) + return PP_ENDIF; + else if (!strcmp(__directive, "error")) + return PP_ERROR; + } + break; + + case 6: + if (__directive[0] == 'i' && !strcmp(__directive, "ifndef")) + return PP_IFNDEF; + else if (__directive[0] == 'd' && !strcmp(__directive, "define")) + return PP_DEFINE; + else if (__directive[0] == 'p' && !strcmp(__directive, "pragma")) + return PP_PRAGMA; + break; + + case 7: + if (__directive[0] == 'i' && !strcmp(__directive, "include")) + return PP_INCLUDE; + else if (!strcmp(__directive, "warning")) + return PP_WARNING; + break; + + case 12: + if (__directive[0] == 'i' && !strcmp(__directive, "include_next")) + return PP_INCLUDE_NEXT; + break; + + default: + break; + } + std::cerr << "** WARNING unknown directive '#" << __directive << "' at " << env.current_file << ":" << env.current_line << std::endl; + return PP_UNKNOWN_DIRECTIVE; +} + +inline bool pp::file_isdir(std::string const &__filename) const +{ + struct stat __st; + if (stat(__filename.c_str(), &__st) == 0) +#if defined(PP_OS_WIN) + return (__st.st_mode & _S_IFDIR) == _S_IFDIR; +#else + return (__st.st_mode & S_IFDIR) == S_IFDIR; +#endif + else + return false; +} + +inline bool pp::file_exists(std::string const &__filename) const +{ + struct stat __st; + return stat(__filename.c_str(), &__st) == 0; +} + +inline FILE *pp::find_include_file(std::string const &__input_filename, std::string *__filepath, + INCLUDE_POLICY __include_policy, bool __skip_current_path) const +{ + assert(__filepath != 0); + assert(! __input_filename.empty()); + + __filepath->assign(__input_filename); + + if (is_absolute(*__filepath) && !file_isdir(*__filepath)) + return std::fopen(__filepath->c_str(), "r"); + + if (! env.current_file.empty()) + _PP_internal::extract_file_path(env.current_file, __filepath); + + if (__include_policy == INCLUDE_LOCAL && ! __skip_current_path) { + std::string __tmp(*__filepath); + __tmp += __input_filename; + + if (file_exists(__tmp) && !file_isdir(__tmp)) { + __filepath->append(__input_filename); + return std::fopen(__filepath->c_str(), "r"); + } + } + + std::vector<std::string>::const_iterator it = include_paths.begin(); + + if (__skip_current_path) { + it = std::find(include_paths.begin(), include_paths.end(), *__filepath); + + if (it != include_paths.end()) + ++it; + + else + it = include_paths.begin(); + } + + for (; it != include_paths.end(); ++it) { + if (__skip_current_path && it == include_paths.begin()) + continue; + + __filepath->assign(*it); + __filepath->append(__input_filename); + + if (file_exists(*__filepath) && !file_isdir(*__filepath)) + return std::fopen(__filepath->c_str(), "r"); + +#ifdef Q_OS_MAC + // try in Framework path on Mac, if there is a path in front + // ### what about escaped slashes? + size_t slashPos = __input_filename.find('/'); + if (slashPos != std::string::npos) { + __filepath->assign(*it); + __filepath->append(__input_filename.substr(0, slashPos)); + __filepath->append(".framework/Headers/"); + __filepath->append(__input_filename.substr(slashPos + 1, std::string::npos)); + + if (file_exists(*__filepath) && !file_isdir(*__filepath)) { + return fopen(__filepath->c_str(), "r"); + } + } +#endif // Q_OS_MAC + } + + return 0; +} + +template <typename _InputIterator, typename _OutputIterator> +_InputIterator pp::handle_directive(char const *__directive, std::size_t __size, + _InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ + __first = skip_blanks(__first, __last); + + PP_DIRECTIVE_TYPE d = find_directive(__directive, __size); + switch (d) { + case PP_UNNAMED_DIRECTIVE: + /* There are many boost headers that include the character '#' + * at the beginning of any line and just do nothing else with + * that unnamed directive. Well, as that's not an error so + * we'll just ignore this unnamed directive for now. + */ + ++__last; + return ++__first; + case PP_DEFINE: + if (! skipping()) + return handle_define(__first, __last); + break; + + case PP_INCLUDE: + case PP_INCLUDE_NEXT: + if (! skipping()) + return handle_include(d == PP_INCLUDE_NEXT, __first, __last, __result); + break; + + case PP_UNDEF: + if (! skipping()) + return handle_undef(__first, __last); + break; + + case PP_ELIF: + return handle_elif(__first, __last); + + case PP_ELSE: + return handle_else(__first, __last); + + case PP_ENDIF: + return handle_endif(__first, __last); + + case PP_IF: + return handle_if(__first, __last); + + case PP_IFDEF: + return handle_ifdef(false, __first, __last); + + case PP_IFNDEF: + return handle_ifdef(true, __first, __last); + + default: + break; + } + + return __first; +} + +template <typename _InputIterator, typename _OutputIterator> +_InputIterator pp::handle_include(bool __skip_current_path, _InputIterator __first, _InputIterator __last, + _OutputIterator __result) +{ + if (pp_isalpha(*__first) || *__first == '_') { + pp_macro_expander expand_include(env); + std::string name; + name.reserve(255); + expand_include(__first, __last, std::back_inserter(name)); + std::string::iterator it = skip_blanks(name.begin(), name.end()); + if (it != name.end() && !(*it == '<' || *it == '"')) { + std::cerr << "** WARNING APIExtractor does not support the use " + "of #include directives without passing either " + "\"<path/to/header.h>\" or \"./path/to/header.h\", " + "for example. Invalid use at " << env.current_file + << ":" << env.current_line << "." << std::endl; + return __last; + } + + handle_include(__skip_current_path, it, name.end(), __result); + return __first; + } + + assert(*__first == '<' || *__first == '"'); + int quote = (*__first == '"') ? '"' : '>'; + ++__first; + + _InputIterator end_name = __first; + for (; end_name != __last; ++end_name) { + assert(*end_name != '\n'); + + if (*end_name == quote) + break; + } + + std::string filename(__first, end_name); + +#ifdef PP_OS_WIN + std::replace(filename.begin(), filename.end(), '/', '\\'); +#endif + + std::string filepath; + FILE *fp = find_include_file(filename, &filepath, quote == '>' ? INCLUDE_GLOBAL : INCLUDE_LOCAL, __skip_current_path); + +#if defined (PP_HOOK_ON_FILE_INCLUDED) + PP_HOOK_ON_FILE_INCLUDED(env.current_file, fp ? filepath : filename, fp); +#endif + + if (fp != 0) { + std::string old_file = env.current_file; + env.current_file = filepath; + int __saved_lines = env.current_line; + + env.current_line = 1; + //output_line (env.current_file, 1, __result); + + file(fp, __result); + + // restore the file name and the line position + env.current_file = old_file; + env.current_line = __saved_lines; + + // sync the buffer + _PP_internal::output_line(env.current_file, env.current_line, __result); + } +#ifndef RPP_JAMBI +// else +// std::cerr << "*** WARNING " << filename << ": No such file or directory" << std::endl; +#endif + + return __first; +} + +template <typename _InputIterator, typename _OutputIterator> +void pp::operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ +#ifndef PP_NO_SMART_HEADER_PROTECTION + std::string __prot; + __prot.reserve(255); + pp_fast_string __tmp(__prot.c_str(), __prot.size()); + + if (find_header_protection(__first, __last, &__prot) + && env.resolve(&__tmp) != 0) { + // std::cerr << "** DEBUG found header protection:" << __prot << std::endl; + return; + } +#endif + + env.current_line = 1; + char __buffer[512]; + + while (true) { + __first = skip_blanks(__first, __last); + env.current_line += skip_blanks.lines; + + if (__first == __last) + break; + else if (*__first == '#') { + assert(*__first == '#'); + __first = skip_blanks(++__first, __last); + env.current_line += skip_blanks.lines; + + _InputIterator end_id = skip_identifier(__first, __last); + env.current_line += skip_identifier.lines; + std::size_t __size = end_id - __first; + + assert(__size < 512); + char *__cp = __buffer; + std::copy(__first, end_id, __cp); + __cp[__size] = '\0'; + + end_id = skip_blanks(end_id, __last); + __first = skip(end_id, __last); + + int was = env.current_line; + (void) handle_directive(__buffer, __size, end_id, __first, __result); + + if (env.current_line != was) { + env.current_line = was; + _PP_internal::output_line(env.current_file, env.current_line, __result); + } + } else if (*__first == '\n') { + // ### compress the line + *__result++ = *__first++; + ++env.current_line; + } else if (skipping()) + __first = skip(__first, __last); + else { + _PP_internal::output_line(env.current_file, env.current_line, __result); + __first = expand(__first, __last, __result); + env.current_line += expand.lines; + + if (expand.generated_lines) + _PP_internal::output_line(env.current_file, env.current_line, __result); + } + } +} + +inline pp::pp(pp_environment &__env): + env(__env), expand(env) +{ + iflevel = 0; + _M_skipping[iflevel] = 0; + _M_true_test[iflevel] = 0; +} + +inline std::back_insert_iterator<std::vector<std::string> > pp::include_paths_inserter() +{ + return std::back_inserter(include_paths); +} + +inline std::vector<std::string>::iterator pp::include_paths_begin() +{ + return include_paths.begin(); +} + +inline std::vector<std::string>::iterator pp::include_paths_end() +{ + return include_paths.end(); +} + +inline std::vector<std::string>::const_iterator pp::include_paths_begin() const +{ + return include_paths.begin(); +} + +inline std::vector<std::string>::const_iterator pp::include_paths_end() const +{ + return include_paths.end(); +} + +inline void pp::push_include_path(std::string const &__path) +{ + if (__path.empty() || __path [__path.size() - 1] != PATH_SEPARATOR) { + std::string __tmp(__path); + __tmp += PATH_SEPARATOR; + include_paths.push_back(__tmp); + } + + else + include_paths.push_back(__path); +} + +template <typename _InputIterator> +_InputIterator pp::handle_define(_InputIterator __first, _InputIterator __last) +{ + pp_macro macro; +#if defined (PP_WITH_MACRO_POSITION) + macro.file = pp_symbol::get(env.current_file); +#endif + std::string definition; + + __first = skip_blanks(__first, __last); + _InputIterator end_macro_name = skip_identifier(__first, __last); + pp_fast_string const *macro_name = pp_symbol::get(__first, end_macro_name); + __first = end_macro_name; + + if (__first != __last && *__first == '(') { + macro.function_like = true; + macro.formals.reserve(5); + + __first = skip_blanks(++__first, __last); // skip '(' + _InputIterator arg_end = skip_identifier(__first, __last); + if (__first != arg_end) + macro.formals.push_back(pp_symbol::get(__first, arg_end)); + + __first = skip_blanks(arg_end, __last); + + if (*__first == '.') { + macro.variadics = true; + while (*__first == '.') + ++__first; + } + + while (__first != __last && *__first == ',') { + __first = skip_blanks(++__first, __last); + + arg_end = skip_identifier(__first, __last); + if (__first != arg_end) + macro.formals.push_back(pp_symbol::get(__first, arg_end)); + + __first = skip_blanks(arg_end, __last); + + if (*__first == '.') { + macro.variadics = true; + while (*__first == '.') + ++__first; + } + } + + assert(*__first == ')'); + ++__first; + } + + __first = skip_blanks(__first, __last); + + /* Note: Sometimes one can include a path between brackets (for + * e.g., when defining a macro or so) so that we cannot simply + * ignore that. The in_path variable will handle this situation. + */ + bool in_path = false; + while (__first != __last && *__first != '\n') { + if ((*__first == '<' || *__first == '"') && + (*(__first + 1) != '*' && *(__first + 1) != '/')) { + in_path = true; + goto skip_path; + } + + if (in_path) { + if (*__first == '>' || *__first == '"') { + in_path = false; + goto skip_path; + } else if (*__first == ',' || *__first == ' ' || *__first == '\\') { + in_path = false; + continue; + } + } + + if (*__first == '/') { + if (*(__first + 1) != '*' && *(__first + 1) != '/') { + in_path = true; + goto skip_path; + } else { + __first = skip_comment_or_divop(__first, __last); + env.current_line += skip_comment_or_divop.lines; + if (__first == __last) + break; + } + } + + if (*__first == '\\') { + _InputIterator __begin = __first; + __begin = skip_blanks(++__begin, __last); + + if (__begin != __last && *__begin == '\n') { + ++macro.lines; + __first = skip_blanks(++__begin, __last); + definition += ' '; + continue; + } + } + +skip_path: + definition += *__first++; + } + + macro.definition = pp_symbol::get(definition); + env.bind(macro_name, macro); + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::skip(_InputIterator __first, _InputIterator __last) +{ + pp_skip_string_literal skip_string_literal; + pp_skip_char_literal skip_char_literal; + + while (__first != __last && *__first != '\n') { + if (*__first == '/') { + __first = skip_comment_or_divop(__first, __last); + env.current_line += skip_comment_or_divop.lines; + } else if (*__first == '"') { + __first = skip_string_literal(__first, __last); + env.current_line += skip_string_literal.lines; + } else if (*__first == '\'') { + __first = skip_char_literal(__first, __last); + env.current_line += skip_char_literal.lines; + } else if (*__first == '\\') { + __first = skip_blanks(++__first, __last); + env.current_line += skip_blanks.lines; + + if (__first != __last && *__first == '\n') { + ++__first; + ++env.current_line; + } + } else + ++__first; + } + + return __first; +} + +inline bool pp::test_if_level() +{ + bool result = !_M_skipping[iflevel++]; + _M_skipping[iflevel] = _M_skipping[iflevel - 1]; + _M_true_test[iflevel] = false; + return result; +} + +inline int pp::skipping() const +{ + return _M_skipping[iflevel]; +} + +template <typename _InputIterator> +_InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, Value *result) +{ + bool expect_paren = false; + int token; + __first = next_token(__first, __last, &token); + + switch (token) { + case TOKEN_NUMBER: + result->set_long(token_value); + break; + + case TOKEN_UNUMBER: + result->set_ulong(token_uvalue); + break; + + case TOKEN_DEFINED: + __first = next_token(__first, __last, &token); + + if (token == '(') { + expect_paren = true; + __first = next_token(__first, __last, &token); + } + + if (token != TOKEN_IDENTIFIER) { + std::cerr << "** WARNING expected ``identifier'' found:" << char(token) << std::endl; + result->set_long(0); + break; + } + + result->set_long(env.resolve(token_text->c_str(), token_text->size()) != 0); + + next_token(__first, __last, &token); // skip '(' + + if (expect_paren) { + _InputIterator next = next_token(__first, __last, &token); + if (token != ')') + std::cerr << "** WARNING expected ``)''" << std::endl; + else + __first = next; + } + break; + + case TOKEN_IDENTIFIER: + result->set_long(0); + break; + + case '-': + __first = eval_primary(__first, __last, result); + result->set_long(- result->l); + return __first; + + case '+': + __first = eval_primary(__first, __last, result); + return __first; + + case '!': + __first = eval_primary(__first, __last, result); + result->set_long(result->is_zero()); + return __first; + + case '(': + __first = eval_constant_expression(__first, __last, result); + next_token(__first, __last, &token); + + if (token != ')') { + std::cerr << "** WARNING expected ``)'' = " << token << " (at " + << env.current_file << ":" << env.current_line + << ")." << std::endl; + } else { + __first = next_token(__first, __last, &token); + } + break; + + default: + result->set_long(0); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_primary(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '*' || token == '/' || token == '%') { + Value value; + __first = eval_primary(next, __last, &value); + + if (token == '*') + result->op_mult(value); + else if (token == '/') { + if (value.is_zero()) { + std::cerr << "** WARNING division by zero" << std::endl; + result->set_long(0); + } else + result->op_div(value); + } else { + if (value.is_zero()) { + std::cerr << "** WARNING division by zero" << std::endl; + result->set_long(0); + } else + result->op_mod(value); + } + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_additive(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_multiplicative(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '+' || token == '-') { + Value value; + __first = eval_multiplicative(next, __last, &value); + + if (token == '+') + result->op_add(value); + else + result->op_sub(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_shift(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_additive(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == TOKEN_LT_LT || token == TOKEN_GT_GT) { + Value value; + __first = eval_additive(next, __last, &value); + + if (token == TOKEN_LT_LT) + result->op_lhs(value); + else + result->op_rhs(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_relational(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_shift(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '<' + || token == '>' + || token == TOKEN_LT_EQ + || token == TOKEN_GT_EQ) { + Value value; + __first = eval_shift(next, __last, &value); + + switch (token) { + default: + assert(0); + break; + + case '<': + result->op_lt(value); + break; + + case '>': + result->op_gt(value); + break; + + case TOKEN_LT_EQ: + result->op_le(value); + break; + + case TOKEN_GT_EQ: + result->op_ge(value); + break; + } + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_equality(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_relational(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == TOKEN_EQ_EQ || token == TOKEN_NOT_EQ) { + Value value; + __first = eval_relational(next, __last, &value); + + if (token == TOKEN_EQ_EQ) + result->op_eq(value); + else + result->op_ne(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_and(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_equality(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '&') { + Value value; + __first = eval_equality(next, __last, &value); + result->op_bit_and(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_xor(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_and(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '^') { + Value value; + __first = eval_and(next, __last, &value); + result->op_bit_xor(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_or(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_xor(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == '|') { + Value value; + __first = eval_xor(next, __last, &value); + result->op_bit_or(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_or(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == TOKEN_AND_AND) { + Value value; + __first = eval_or(next, __last, &value); + result->op_and(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_logical_and(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + while (token == TOKEN_OR_OR) { + Value value; + __first = eval_logical_and(next, __last, &value); + result->op_or(value); + next = next_token(__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_logical_or(__first, __last, result); + + int token; + _InputIterator next = next_token(__first, __last, &token); + + if (token == '?') { + Value left_value; + __first = eval_constant_expression(next, __last, &left_value); + __first = skip_blanks(__first, __last); + + __first = next_token(__first, __last, &token); + if (token == ':') { + Value right_value; + __first = eval_constant_expression(__first, __last, &right_value); + + *result = !result->is_zero() ? left_value : right_value; + } else { + std::cerr << "** WARNING expected ``:'' = " << int (token) << std::endl; + *result = left_value; + } + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_expression(_InputIterator __first, _InputIterator __last, Value *result) +{ + return __first = eval_constant_expression(skip_blanks(__first, __last), __last, result); +} + +template <typename _InputIterator> +_InputIterator pp::handle_if(_InputIterator __first, _InputIterator __last) +{ + if (test_if_level()) { + pp_macro_expander expand_condition(env); + std::string condition; + condition.reserve(255); + expand_condition(skip_blanks(__first, __last), __last, std::back_inserter(condition)); + + Value result; + result.set_long(0); + eval_expression(condition.c_str(), condition.c_str() + condition.size(), &result); + + _M_true_test[iflevel] = !result.is_zero(); + _M_skipping[iflevel] = result.is_zero(); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_else(_InputIterator __first, _InputIterator /*__last*/) +{ + if (iflevel == 0 && !skipping()) { + std::cerr << "** WARNING #else without #if" << std::endl; + } else if (iflevel > 0 && _M_skipping[iflevel - 1]) { + _M_skipping[iflevel] = true; + } else { + _M_skipping[iflevel] = _M_true_test[iflevel]; + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_elif(_InputIterator __first, _InputIterator __last) +{ + assert(iflevel > 0); + + if (iflevel == 0 && !skipping()) { + std::cerr << "** WARNING #else without #if" << std::endl; + } else if (!_M_true_test[iflevel] && !_M_skipping[iflevel - 1]) { + Value result; + __first = eval_expression(__first, __last, &result); + _M_true_test[iflevel] = !result.is_zero(); + _M_skipping[iflevel] = result.is_zero(); + } else { + _M_skipping[iflevel] = true; + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_endif(_InputIterator __first, _InputIterator /*__last*/) +{ + if (iflevel == 0 && !skipping()) { + std::cerr << "** WARNING #endif without #if" << std::endl; + } else { + _M_skipping[iflevel] = 0; + _M_true_test[iflevel] = 0; + + --iflevel; + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_ifdef(bool check_undefined, _InputIterator __first, _InputIterator __last) +{ + if (test_if_level()) { + _InputIterator end_macro_name = skip_identifier(__first, __last); + + std::size_t __size; +#if defined(__SUNPRO_CC) + std::distance(__first, end_macro_name, __size); +#else + __size = std::distance(__first, end_macro_name); +#endif + assert(__size < 256); + + char __buffer [256]; + std::copy(__first, end_macro_name, __buffer); + + bool value = env.resolve(__buffer, __size) != 0; + + __first = end_macro_name; + + if (check_undefined) + value = !value; + + _M_true_test[iflevel] = value; + _M_skipping[iflevel] = !value; + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_undef(_InputIterator __first, _InputIterator __last) +{ + __first = skip_blanks(__first, __last); + _InputIterator end_macro_name = skip_identifier(__first, __last); + assert(end_macro_name != __first); + + std::size_t __size; +#if defined(__SUNPRO_CC) + std::distance(__first, end_macro_name, __size); +#else + __size = std::distance(__first, end_macro_name); +#endif + + assert(__size < 256); + + char __buffer [256]; + std::copy(__first, end_macro_name, __buffer); + + pp_fast_string const __tmp(__buffer, __size); + env.unbind(&__tmp); + + __first = end_macro_name; + + return __first; +} + +template <typename _InputIterator> +char pp::peek_char(_InputIterator __first, _InputIterator __last) +{ + if (__first == __last) + return 0; + + return *++__first; +} + +template <typename _InputIterator> +_InputIterator pp::next_token(_InputIterator __first, _InputIterator __last, int *kind) +{ + __first = skip_blanks(__first, __last); + + if (__first == __last) { + *kind = 0; + return __first; + } + + char ch = *__first; + char ch2 = peek_char(__first, __last); + + switch (ch) { + case '/': + if (ch2 == '/' || ch2 == '*') { + __first = skip_comment_or_divop(__first, __last); + return next_token(__first, __last, kind); + } + ++__first; + *kind = '/'; + break; + + case '<': + ++__first; + if (ch2 == '<') { + ++__first; + *kind = TOKEN_LT_LT; + } else if (ch2 == '=') { + ++__first; + *kind = TOKEN_LT_EQ; + } else + *kind = '<'; + + return __first; + + case '>': + ++__first; + if (ch2 == '>') { + ++__first; + *kind = TOKEN_GT_GT; + } else if (ch2 == '=') { + ++__first; + *kind = TOKEN_GT_EQ; + } else + *kind = '>'; + + return __first; + + case '!': + ++__first; + if (ch2 == '=') { + ++__first; + *kind = TOKEN_NOT_EQ; + } else + *kind = '!'; + + return __first; + + case '=': + ++__first; + if (ch2 == '=') { + ++__first; + *kind = TOKEN_EQ_EQ; + } else + *kind = '='; + + return __first; + + case '|': + ++__first; + if (ch2 == '|') { + ++__first; + *kind = TOKEN_OR_OR; + } else + *kind = '|'; + + return __first; + + case '&': + ++__first; + if (ch2 == '&') { + ++__first; + *kind = TOKEN_AND_AND; + } else + *kind = '&'; + + return __first; + + default: + if (pp_isalpha(ch) || ch == '_') { + _InputIterator end = skip_identifier(__first, __last); + _M_current_text.assign(__first, end); + + token_text = &_M_current_text; + __first = end; + + if (*token_text == "defined") + *kind = TOKEN_DEFINED; + else + *kind = TOKEN_IDENTIFIER; + } else if (pp_isdigit(ch)) { + _InputIterator end = skip_number(__first, __last); + std::string __str(__first, __last); + char ch = __str [__str.size() - 1]; + if (ch == 'u' || ch == 'U') { + token_uvalue = strtoul(__str.c_str(), 0, 0); + *kind = TOKEN_UNUMBER; + } else { + token_value = strtol(__str.c_str(), 0, 0); + *kind = TOKEN_NUMBER; + } + __first = end; + } else + *kind = *__first++; + } + + return __first; +} + +} // namespace rpp + +#endif // PP_ENGINE_BITS_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-engine.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-engine.h new file mode 100644 index 000000000..689d7720e --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-engine.h @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** 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 PP_ENGINE_H +#define PP_ENGINE_H + +#include <string> +#include <vector> +#include "pp-scanner.h" +#include "pp-macro-expander.h" +#include "pp-environment.h" + +namespace rpp +{ + +struct Value { + Value() : kind(Kind_Long), l(0) {} + + enum Kind { + Kind_Long, + Kind_ULong, + }; + + Kind kind; + + union { + long l; + unsigned long ul; + }; + + inline bool is_ulong() const { + return kind == Kind_ULong; + } + + inline void set_ulong(unsigned long v) { + ul = v; + kind = Kind_ULong; + } + + inline void set_long(long v) { + l = v; + kind = Kind_Long; + } + + inline bool is_zero() const { + return l == 0; + } + +#define PP_DEFINE_BIN_OP(name, op) \ + inline Value &name (const Value &other) \ + { \ + if (is_ulong () || other.is_ulong ()) \ + set_ulong (ul op other.ul); \ + else \ + set_long (l op other.l); \ + return *this; \ + } + + PP_DEFINE_BIN_OP(op_add, +) + PP_DEFINE_BIN_OP(op_sub, -) + PP_DEFINE_BIN_OP(op_mult, *) + PP_DEFINE_BIN_OP(op_div, /) + PP_DEFINE_BIN_OP(op_mod, %) + PP_DEFINE_BIN_OP(op_lhs, <<) + PP_DEFINE_BIN_OP(op_rhs, >>) + PP_DEFINE_BIN_OP(op_lt, <) + PP_DEFINE_BIN_OP(op_gt, >) + PP_DEFINE_BIN_OP(op_le, <=) + PP_DEFINE_BIN_OP(op_ge, >=) + PP_DEFINE_BIN_OP(op_eq, ==) + PP_DEFINE_BIN_OP(op_ne, !=) + PP_DEFINE_BIN_OP(op_bit_and, &) + PP_DEFINE_BIN_OP(op_bit_or, |) + PP_DEFINE_BIN_OP(op_bit_xor, ^) + PP_DEFINE_BIN_OP(op_and, &&) + PP_DEFINE_BIN_OP(op_or, ||) + +#undef PP_DEFINE_BIN_OP +}; + +class pp +{ + pp_environment &env; + pp_macro_expander expand; + pp_skip_identifier skip_identifier; + pp_skip_comment_or_divop skip_comment_or_divop; + pp_skip_blanks skip_blanks; + pp_skip_number skip_number; + std::vector<std::string> include_paths; + std::string _M_current_text; + + enum { MAX_LEVEL = 512 }; + int _M_skipping[MAX_LEVEL]; + int _M_true_test[MAX_LEVEL]; + int iflevel; + + union { + long token_value; + unsigned long token_uvalue; + std::string *token_text; + }; + + enum INCLUDE_POLICY { + INCLUDE_GLOBAL, + INCLUDE_LOCAL + }; + + enum TOKEN_TYPE { + TOKEN_NUMBER = 1000, + TOKEN_UNUMBER, + TOKEN_IDENTIFIER, + TOKEN_DEFINED, + TOKEN_LT_LT, + TOKEN_LT_EQ, + TOKEN_GT_GT, + TOKEN_GT_EQ, + TOKEN_EQ_EQ, + TOKEN_NOT_EQ, + TOKEN_OR_OR, + TOKEN_AND_AND, + }; + + enum PP_DIRECTIVE_TYPE { + PP_UNKNOWN_DIRECTIVE, + PP_UNNAMED_DIRECTIVE, + PP_DEFINE, + PP_INCLUDE, + PP_INCLUDE_NEXT, + PP_ELIF, + PP_ELSE, + PP_ENDIF, + PP_IF, + PP_IFDEF, + PP_IFNDEF, + PP_UNDEF, + PP_PRAGMA, + PP_ERROR, + PP_WARNING + }; + +public: + pp(pp_environment &__env); + + inline std::back_insert_iterator<std::vector<std::string> > include_paths_inserter(); + + inline void push_include_path(std::string const &__path); + + inline std::vector<std::string>::iterator include_paths_begin(); + inline std::vector<std::string>::iterator include_paths_end(); + + inline std::vector<std::string>::const_iterator include_paths_begin() const; + inline std::vector<std::string>::const_iterator include_paths_end() const; + + template <typename _InputIterator> + inline _InputIterator eval_expression(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _OutputIterator> + void file(std::string const &filename, _OutputIterator __result); + + template <typename _OutputIterator> + void file(FILE *fp, _OutputIterator __result); + + template <typename _InputIterator, typename _OutputIterator> + void operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result); + +private: + inline bool file_isdir(std::string const &__filename) const; + inline bool file_exists(std::string const &__filename) const; + FILE *find_include_file(std::string const &__filename, std::string *__filepath, + INCLUDE_POLICY __include_policy, bool __skip_current_path = false) const; + + inline int skipping() const; + bool test_if_level(); + + inline std::string fix_file_path(std::string const &filename) const; + inline bool is_absolute(std::string const &filename) const; + + PP_DIRECTIVE_TYPE find_directive(char const *__directive, std::size_t __size) const; + + template <typename _InputIterator> + bool find_header_protection(_InputIterator __first, _InputIterator __last, std::string *__prot); + + template <typename _InputIterator> + _InputIterator skip(_InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + _InputIterator eval_primary(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_additive(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_shift(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_relational(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_equality(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_and(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_xor(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_or(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator> + _InputIterator eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result); + + template <typename _InputIterator, typename _OutputIterator> + _InputIterator handle_directive(char const *__directive, std::size_t __size, + _InputIterator __first, _InputIterator __last, _OutputIterator __result); + + template <typename _InputIterator, typename _OutputIterator> + _InputIterator handle_include(bool skip_current_path, _InputIterator __first, _InputIterator __last, + _OutputIterator __result); + + template <typename _InputIterator> + _InputIterator handle_define(_InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + _InputIterator handle_if(_InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + _InputIterator handle_else(_InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + _InputIterator handle_elif(_InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + _InputIterator handle_endif(_InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + _InputIterator handle_ifdef(bool check_undefined, _InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + _InputIterator handle_undef(_InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + inline char peek_char(_InputIterator __first, _InputIterator __last); + + template <typename _InputIterator> + _InputIterator next_token(_InputIterator __first, _InputIterator __last, int *kind); +}; + +} // namespace rpp + +#endif // PP_ENGINE_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-environment.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-environment.h new file mode 100644 index 000000000..23f22e483 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-environment.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** 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 PP_ENVIRONMENT_H +#define PP_ENVIRONMENT_H + +#include <vector> +#include <string> +#include <cstring> +#include "pp-macro.h" + +namespace rpp +{ + +class pp_environment +{ +public: + typedef std::vector<pp_macro*>::const_iterator const_iterator; + +public: + pp_environment(): + current_line(0), + _M_hash_size(4093) { + _M_base = (pp_macro **) memset(new pp_macro* [_M_hash_size], 0, _M_hash_size * sizeof(pp_macro*)); + } + + ~pp_environment() { + for (std::size_t i = 0; i < _M_macros.size(); ++i) + delete _M_macros [i]; + + delete [] _M_base; + } + + const_iterator first_macro() const { + return _M_macros.begin(); + } + const_iterator last_macro() const { + return _M_macros.end(); + } + + inline void bind(pp_fast_string const *__name, pp_macro const &__macro) { + std::size_t h = hash_code(*__name) % _M_hash_size; + pp_macro *m = new pp_macro(__macro); + m->name = __name; + m->next = _M_base [h]; + m->hash_code = h; + _M_base [h] = m; + + _M_macros.push_back(m); + + if (_M_macros.size() == _M_hash_size) + rehash(); + } + + inline void unbind(pp_fast_string const *__name) { + if (pp_macro *m = resolve(__name)) + m->hidden = true; + } + + inline void unbind(char const *__s, std::size_t __size) { + pp_fast_string __tmp(__s, __size); + unbind(&__tmp); + } + + inline pp_macro *resolve(pp_fast_string const *__name) const { + std::size_t h = hash_code(*__name) % _M_hash_size; + pp_macro *it = _M_base [h]; + + while (it && it->name && it->hash_code == h && (*it->name != *__name || it->hidden)) + it = it->next; + + return it; + } + + inline pp_macro *resolve(char const *__data, std::size_t __size) const { + pp_fast_string const __tmp(__data, __size); + return resolve(&__tmp); + } + + std::string current_file; + int current_line; + +private: + inline std::size_t hash_code(pp_fast_string const &s) const { + std::size_t hash_value = 0; + + for (std::size_t i = 0; i < s.size(); ++i) + hash_value = (hash_value << 5) - hash_value + s.at(i); + + return hash_value; + } + + void rehash() { + delete[] _M_base; + + _M_hash_size <<= 1; + + _M_base = (pp_macro **) memset(new pp_macro* [_M_hash_size], 0, _M_hash_size * sizeof(pp_macro*)); + for (std::size_t index = 0; index < _M_macros.size(); ++index) { + pp_macro *elt = _M_macros [index]; + std::size_t h = hash_code(*elt->name) % _M_hash_size; + elt->next = _M_base [h]; + elt->hash_code = h; + _M_base [h] = elt; + } + } + +private: + std::vector<pp_macro*> _M_macros; + pp_macro **_M_base; + std::size_t _M_hash_size; +}; + +} // namespace rpp + +#endif // PP_ENVIRONMENT_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-fwd.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-fwd.h new file mode 100644 index 000000000..2814b6d44 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-fwd.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** 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 PP_FWD_H +#define PP_FWD_H + +namespace rpp +{ + +template <typename _CharT> class pp_string; + +typedef pp_string<char> pp_fast_string; + +} // namespace rpp + +#endif // PP_FWD_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-internal.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-internal.h new file mode 100644 index 000000000..33efa0c27 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-internal.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** 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 PP_INTERNAL_H +#define PP_INTERNAL_H + +#include <algorithm> +#include <string> +#include "pp.h" + +namespace rpp +{ + +namespace _PP_internal +{ + +inline void extract_file_path(const std::string &__filename, std::string *__filepath) +{ + std::size_t __index = __filename.rfind(PATH_SEPARATOR); + + if (__index == std::string::npos) + *__filepath = "/"; + + else + __filepath->assign(__filename, 0, __index + 1); +} + +template <typename _OutputIterator> +void output_line(const std::string &__filename, int __line, _OutputIterator __result) +{ + std::string __msg; + + __msg += "# "; + + char __line_descr[16]; + pp_snprintf(__line_descr, 16, "%d", __line); + __msg += __line_descr; + + __msg += " \""; + + if (__filename.empty()) + __msg += "<internal>"; + else + __msg += __filename; + + __msg += "\"\n"; + std::copy(__msg.begin(), __msg.end(), __result); +} + +template <typename _InputIterator> +inline bool comment_p(_InputIterator __first, _InputIterator __last) /*const*/ +{ + if (__first == __last) + return false; + + if (*__first != '/') + return false; + + if (++__first == __last) + return false; + + return (*__first == '/' || *__first == '*'); +} + +struct _Compare_string: public std::binary_function<bool, pp_fast_string const *, pp_fast_string const *> { + inline bool operator()(pp_fast_string const *__lhs, pp_fast_string const *__rhs) const { + return *__lhs < *__rhs; + } +}; + +struct _Equal_to_string: public std::binary_function<bool, pp_fast_string const *, pp_fast_string const *> { + inline bool operator()(pp_fast_string const *__lhs, pp_fast_string const *__rhs) const { + return *__lhs == *__rhs; + } +}; + +struct _Hash_string: public std::unary_function<std::size_t, pp_fast_string const *> { + inline std::size_t operator()(pp_fast_string const *__s) const { + char const *__ptr = __s->begin(); + std::size_t __size = __s->size(); + std::size_t __h = 0; + + for (std::size_t i = 0; i < __size; ++i) + __h = (__h << 5) - __h + __ptr [i]; + + return __h; + } +}; + +} // _PP_internal + +} // namespace rpp + +#endif // PP_INTERNAL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-iterator.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-iterator.h new file mode 100644 index 000000000..35964fea4 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-iterator.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** 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 PP_ITERATOR_H +#define PP_ITERATOR_H + +#include <iterator> + +namespace rpp +{ + +class pp_null_output_iterator + : public std::iterator<std::output_iterator_tag, void, void, void, void> +{ +public: + pp_null_output_iterator() {} + + template <typename _Tp> + pp_null_output_iterator &operator=(_Tp const &) { + return *this; + } + + inline pp_null_output_iterator &operator *() { + return *this; + } + inline pp_null_output_iterator &operator ++ () { + return *this; + } + inline pp_null_output_iterator operator ++ (int) { + return *this; + } +}; + +template <typename _Container> +class pp_output_iterator + : public std::iterator<std::output_iterator_tag, void, void, void, void> +{ + std::string &_M_result; + +public: + explicit pp_output_iterator(std::string &__result): + _M_result(__result) {} + + inline pp_output_iterator<_Container>& operator=(const pp_output_iterator<_Container>& other) + { + _M_result = other._M_result; + return *this; + } + + inline pp_output_iterator &operator=(typename _Container::const_reference __v) { + if (_M_result.capacity() == _M_result.size()) + _M_result.reserve(_M_result.capacity() << 2); + + _M_result.push_back(__v); + return *this; + } + + inline pp_output_iterator &operator *() { + return *this; + } + inline pp_output_iterator &operator ++ () { + return *this; + } + inline pp_output_iterator operator ++ (int) { + return *this; + } +}; + +} // namespace rpp + +#endif // PP_ITERATOR_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-macro-expander.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-macro-expander.h new file mode 100644 index 000000000..db93c3214 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-macro-expander.h @@ -0,0 +1,356 @@ +/**************************************************************************** +** +** 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 PP_MACRO_EXPANDER_H +#define PP_MACRO_EXPANDER_H + +namespace rpp +{ + +struct pp_frame { + pp_macro *expanding_macro; + std::vector<std::string> *actuals; + + pp_frame(pp_macro *__expanding_macro, std::vector<std::string> *__actuals): + expanding_macro(__expanding_macro), actuals(__actuals) {} +}; + +class pp_macro_expander +{ + pp_environment &env; + pp_frame *frame; + + pp_skip_number skip_number; + pp_skip_identifier skip_identifier; + pp_skip_string_literal skip_string_literal; + pp_skip_char_literal skip_char_literal; + pp_skip_argument skip_argument; + pp_skip_comment_or_divop skip_comment_or_divop; + pp_skip_blanks skip_blanks; + pp_skip_whitespaces skip_whitespaces; + + std::string const *resolve_formal(pp_fast_string const *__name) { + assert(__name != 0); + + if (! frame) + return 0; + + assert(frame->expanding_macro != 0); + + std::vector<pp_fast_string const *> const formals = frame->expanding_macro->formals; + for (std::size_t index = 0; index < formals.size(); ++index) { + pp_fast_string const *formal = formals[index]; + + if (*formal != *__name) + continue; + + else if (frame->actuals && index < frame->actuals->size()) + return &(*frame->actuals)[index]; + + else + assert(0); // internal error? + } + + return 0; + } + +public: // attributes + int lines; + int generated_lines; + +public: + pp_macro_expander(pp_environment &__env, pp_frame *__frame = 0): + env(__env), frame(__frame), lines(0), generated_lines(0) {} + + template <typename _InputIterator, typename _OutputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { + generated_lines = 0; + __first = skip_blanks(__first, __last); + lines = skip_blanks.lines; + + while (__first != __last) { + if (*__first == '\n') { + *__result++ = *__first; + ++lines; + + __first = skip_blanks(++__first, __last); + lines += skip_blanks.lines; + + if (__first != __last && *__first == '#') + break; + } else if (*__first == '#') { + __first = skip_blanks(++__first, __last); + lines += skip_blanks.lines; + + _InputIterator end_id = skip_identifier(__first, __last); + + // ### rewrite: not safe + char name_buffer[512], *cp = name_buffer; + std::copy(__first, end_id, cp); + std::size_t name_size = end_id - __first; + name_buffer[name_size] = '\0'; + + pp_fast_string fast_name(name_buffer, name_size); + + if (std::string const *actual = resolve_formal(&fast_name)) { + *__result++ = '\"'; + + for (std::string::const_iterator it = skip_whitespaces(actual->begin(), actual->end()); + it != actual->end(); ++it) { + if (*it == '"') { + *__result++ = '\\'; + *__result++ = *it; + } + + else if (*it == '\n') { + *__result++ = '"'; + *__result++ = '\n'; + *__result++ = '"'; + } + + else + *__result++ = *it; + } + + *__result++ = '\"'; + __first = end_id; + } else + *__result++ = '#'; // ### warning message? + } else if (*__first == '\"') { + _InputIterator next_pos = skip_string_literal(__first, __last); + lines += skip_string_literal.lines; + std::copy(__first, next_pos, __result); + __first = next_pos; + } else if (*__first == '\'') { + _InputIterator next_pos = skip_char_literal(__first, __last); + lines += skip_char_literal.lines; + std::copy(__first, next_pos, __result); + __first = next_pos; + } else if (_PP_internal::comment_p(__first, __last)) { + __first = skip_comment_or_divop(__first, __last); + int n = skip_comment_or_divop.lines; + lines += n; + + while (n-- > 0) + *__result++ = '\n'; + } else if (pp_isspace(*__first)) { + for (; __first != __last; ++__first) { + if (*__first == '\n' || !pp_isspace(*__first)) + break; + } + + *__result = ' '; + } else if (pp_isdigit(*__first)) { + _InputIterator next_pos = skip_number(__first, __last); + lines += skip_number.lines; + std::copy(__first, next_pos, __result); + __first = next_pos; + } else if (pp_isalpha(*__first) || *__first == '_') { + _InputIterator name_begin = __first; + _InputIterator name_end = skip_identifier(__first, __last); + __first = name_end; // advance + + // search for the paste token + _InputIterator next = skip_blanks(__first, __last); + if (next != __last && *next == '#') { + ++next; + if (next != __last && *next == '#') + __first = skip_blanks(++next, __last); + } + + // ### rewrite: not safe + + std::ptrdiff_t name_size; +#if defined(__SUNPRO_CC) + std::distance(name_begin, name_end, name_size); +#else + name_size = std::distance(name_begin, name_end); +#endif + assert(name_size >= 0 && name_size < 512); + + char name_buffer[512], *cp = name_buffer; + std::size_t __size = name_end - name_begin; + std::copy(name_begin, name_end, cp); + name_buffer[__size] = '\0'; + + pp_fast_string fast_name(name_buffer, name_size); + + if (std::string const *actual = resolve_formal(&fast_name)) { + std::copy(actual->begin(), actual->end(), __result); + continue; + } + + static bool hide_next = false; // ### remove me + + pp_macro *macro = env.resolve(name_buffer, name_size); + if (! macro || macro->hidden || hide_next) { + hide_next = ! strcmp(name_buffer, "defined"); + + if (__size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_') { + if (! strcmp(name_buffer, "__LINE__")) { + char buf [16]; + char *end = buf + pp_snprintf(buf, 16, "%d", env.current_line + lines); + + std::copy(&buf [0], end, __result); + continue; + } + + else if (! strcmp(name_buffer, "__FILE__")) { + __result++ = '"'; + std::copy(env.current_file.begin(), env.current_file.end(), __result); // ### quote + __result++ = '"'; + continue; + } + } + + std::copy(name_begin, name_end, __result); + continue; + } + + if (! macro->function_like) { + pp_macro *m = 0; + + if (macro->definition) { + macro->hidden = true; + + std::string __tmp; + __tmp.reserve(256); + + pp_macro_expander expand_macro(env); + expand_macro(macro->definition->begin(), macro->definition->end(), std::back_inserter(__tmp)); + generated_lines += expand_macro.lines; + + if (! __tmp.empty()) { + std::string::iterator __begin_id = skip_whitespaces(__tmp.begin(), __tmp.end()); + std::string::iterator __end_id = skip_identifier(__begin_id, __tmp.end()); + + if (__end_id == __tmp.end()) { + std::string __id; + __id.assign(__begin_id, __end_id); + + std::size_t x; +#if defined(__SUNPRO_CC) + std::distance(__begin_id, __end_id, x); +#else + x = std::distance(__begin_id, __end_id); +#endif + m = env.resolve(__id.c_str(), x); + } + + if (! m) + std::copy(__tmp.begin(), __tmp.end(), __result); + } + + macro->hidden = false; + } + + if (! m) + continue; + + macro = m; + } + + // function like macro + _InputIterator arg_it = skip_whitespaces(__first, __last); + + if (arg_it == __last || *arg_it != '(') { + std::copy(name_begin, name_end, __result); + lines += skip_whitespaces.lines; + __first = arg_it; + continue; + } + + std::vector<std::string> actuals; + actuals.reserve(5); + ++arg_it; // skip '(' + + pp_macro_expander expand_actual(env, frame); + + _InputIterator arg_end = skip_argument_variadics(actuals, macro, arg_it, __last); + if (arg_it != arg_end) { + std::string actual(arg_it, arg_end); + actuals.resize(actuals.size() + 1); + actuals.back().reserve(255); + expand_actual(actual.begin(), actual.end(), std::back_inserter(actuals.back())); + arg_it = arg_end; + } + + while (arg_it != __last && *arg_end == ',') { + ++arg_it; // skip ',' + + arg_end = skip_argument_variadics(actuals, macro, arg_it, __last); + std::string actual(arg_it, arg_end); + actuals.resize(actuals.size() + 1); + actuals.back().reserve(255); + expand_actual(actual.begin(), actual.end(), std::back_inserter(actuals.back())); + arg_it = arg_end; + } + + assert(arg_it != __last && *arg_it == ')'); + + ++arg_it; // skip ')' + __first = arg_it; + +#if 0 // ### enable me + assert((macro->variadics && macro->formals.size() >= actuals.size()) + || macro->formals.size() == actuals.size()); +#endif + + pp_frame frame(macro, &actuals); + pp_macro_expander expand_macro(env, &frame); + macro->hidden = true; + expand_macro(macro->definition->begin(), macro->definition->end(), __result); + macro->hidden = false; + generated_lines += expand_macro.lines; + } else + *__result++ = *__first++; + } + + return __first; + } + + template <typename _InputIterator> + _InputIterator skip_argument_variadics(std::vector<std::string> const &__actuals, pp_macro *__macro, + _InputIterator __first, _InputIterator __last) { + _InputIterator arg_end = skip_argument(__first, __last); + + while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ',' + && (__actuals.size() + 1) == __macro->formals.size()) { + arg_end = skip_argument(++arg_end, __last); + } + + return arg_end; + } +}; + +} // namespace rpp + +#endif // PP_MACRO_EXPANDER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-macro.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-macro.h new file mode 100644 index 000000000..9e95840a1 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-macro.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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 PP_MACRO_H +#define PP_MACRO_H + +#include <vector> +#include "pp-fwd.h" + +namespace rpp +{ + +struct pp_macro { +#if defined (PP_WITH_MACRO_POSITION) + pp_fast_string const *file; +#endif + pp_fast_string const *name; + pp_fast_string const *definition; + std::vector<pp_fast_string const *> formals; + + union { + int unsigned state; + + struct { + int unsigned hidden: 1; + int unsigned function_like: 1; + int unsigned variadics: 1; + }; + }; + + int lines; + pp_macro *next; + std::size_t hash_code; + + inline pp_macro(): +#if defined (PP_WITH_MACRO_POSITION) + file(0), +#endif + name(0), + definition(0), + state(0), + lines(0), + next(0), + hash_code(0) {} +}; + +} // namespace rpp + +#endif // PP_MACRO_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-qt-configuration b/sources/shiboken2/ApiExtractor/parser/rpp/pp-qt-configuration new file mode 100644 index 000000000..ba356c323 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-qt-configuration @@ -0,0 +1,24 @@ +#define __cplusplus 1 + +#define __STDC__ 1 + +// Qt +#define QOBJECTDEFS_H + +// not yet supported +#define Q_SLOTS slots +#define Q_SIGNALS signals +#define Q_FLAGS(a) +#define Q_PRIVATE_SLOT(a, b) +#define Q_DECLARE_INTERFACE(a,b) +#define Q_INTERFACES(a) +#define Q_GADGET +#define Q_OVERRIDE(a) +#define Q_OS_OS2 +#define Q_NO_USING_KEYWORD +#define QT_NO_QOBJECT_CHECK +#define QT_NO_MEMBER_TEMPLATES +// There are symbols in Qt that exist in Debug but +// not in release +#define QT_NO_DEBUG + diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-scanner.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-scanner.h new file mode 100644 index 000000000..0c5007e0f --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-scanner.h @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** 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 PP_SCANNER_H +#define PP_SCANNER_H + +#include "pp-cctype.h" +#include <cassert> + +namespace rpp +{ + +struct pp_skip_blanks { + int lines; + + template <typename _InputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + if (*__first == '\\') { + _InputIterator __begin = __first; + ++__begin; + + if (__begin != __last && *__begin == '\n') + ++__first; + else + break; + } else if (*__first == '\n' || !pp_isspace(*__first)) + break; + } + + return __first; + } +}; + +struct pp_skip_whitespaces { + int lines; + + template <typename _InputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + if (! pp_isspace(*__first)) + break; + } + + return __first; + } +}; + +struct pp_skip_comment_or_divop { + int lines; + + template <typename _InputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + enum { + MAYBE_BEGIN, + BEGIN, + MAYBE_END, + END, + IN_COMMENT, + IN_CXX_COMMENT + } state(MAYBE_BEGIN); + + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + switch (state) { + default: + assert(0); + break; + + case MAYBE_BEGIN: + if (*__first != '/') + return __first; + + state = BEGIN; + break; + + case BEGIN: + if (*__first == '*') + state = IN_COMMENT; + else if (*__first == '/') + state = IN_CXX_COMMENT; + else + return __first; + break; + + case IN_COMMENT: + if (*__first == '*') + state = MAYBE_END; + break; + + case IN_CXX_COMMENT: + if (*__first == '\n') + return __first; + break; + + case MAYBE_END: + if (*__first == '/') + state = END; + else if (*__first != '*') + state = IN_COMMENT; + break; + + case END: + return __first; + } + } + + return __first; + } +}; + +struct pp_skip_identifier { + int lines; + + template <typename _InputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + if (! pp_isalnum(*__first) && *__first != '_') + break; + } + + return __first; + } +}; + +struct pp_skip_number { + int lines; + + template <typename _InputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + if (! pp_isalnum(*__first) && *__first != '.') + break; + } + + return __first; + } +}; + +struct pp_skip_string_literal { + int lines; + + template <typename _InputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + enum { + BEGIN, + IN_STRING, + QUOTE, + END + } state(BEGIN); + + lines = 0; + + for (; __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + switch (state) { + default: + assert(0); + break; + + case BEGIN: + if (*__first != '\"') + return __first; + state = IN_STRING; + break; + + case IN_STRING: + assert(*__first != '\n'); + + if (*__first == '\"') + state = END; + else if (*__first == '\\') + state = QUOTE; + break; + + case QUOTE: + state = IN_STRING; + break; + + case END: + return __first; + } + } + + return __first; + } +}; + +struct pp_skip_char_literal { + int lines; + + template <typename _InputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + enum { + BEGIN, + IN_STRING, + QUOTE, + END + } state(BEGIN); + + lines = 0; + + for (; state != END && __first != __last; lines += (*__first != '\n' ? 0 : 1), ++__first) { + switch (state) { + default: + assert(0); + break; + + case BEGIN: + if (*__first != '\'') + return __first; + state = IN_STRING; + break; + + case IN_STRING: + assert(*__first != '\n'); + + if (*__first == '\'') + state = END; + else if (*__first == '\\') + state = QUOTE; + break; + + case QUOTE: + state = IN_STRING; + break; + } + } + + return __first; + } +}; + +struct pp_skip_argument { + pp_skip_identifier skip_number; + pp_skip_identifier skip_identifier; + pp_skip_string_literal skip_string_literal; + pp_skip_char_literal skip_char_literal; + pp_skip_comment_or_divop skip_comment_or_divop; + int lines; + + template <typename _InputIterator> + _InputIterator operator()(_InputIterator __first, _InputIterator __last) { + int depth = 0; + lines = 0; + + while (__first != __last) { + if (!depth && (*__first == ')' || *__first == ',')) + break; + else if (*__first == '(') + ++depth, ++__first; + else if (*__first == ')') + --depth, ++__first; + else if (*__first == '\"') { + __first = skip_string_literal(__first, __last); + lines += skip_string_literal.lines; + } else if (*__first == '\'') { + __first = skip_char_literal(__first, __last); + lines += skip_char_literal.lines; + } else if (*__first == '/') { + __first = skip_comment_or_divop(__first, __last); + lines += skip_comment_or_divop.lines; + } else if (pp_isalpha(*__first) || *__first == '_') { + __first = skip_identifier(__first, __last); + lines += skip_identifier.lines; + } else if (pp_isdigit(*__first)) { + __first = skip_number(__first, __last); + lines += skip_number.lines; + } else if (*__first == '\n') { + ++__first; + ++lines; + } else + ++__first; + } + + return __first; + } +}; + +} // namespace rpp + +#endif // PP_SCANNER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-string.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-string.h new file mode 100644 index 000000000..25db0389a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-string.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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 PP_STRING_H +#define PP_STRING_H + +namespace rpp +{ + +template <typename _CharT> +class pp_string +{ + typedef std::char_traits<_CharT> traits_type; + typedef std::size_t size_type; + + _CharT const *_M_begin; + std::size_t _M_size; + +public: + inline pp_string(): + _M_begin(0), _M_size(0) {} + + explicit pp_string(std::string const &__s): + _M_begin(__s.c_str()), _M_size(__s.size()) {} + + inline pp_string(_CharT const *__begin, std::size_t __size): + _M_begin(__begin), _M_size(__size) {} + + inline _CharT const *begin() const { + return _M_begin; + } + inline _CharT const *end() const { + return _M_begin + _M_size; + } + + inline _CharT at(std::size_t index) const { + return _M_begin [index]; + } + + inline std::size_t size() const { + return _M_size; + } + + inline int compare(pp_string const &__other) const { + size_type const __size = this->size(); + size_type const __osize = __other.size(); + size_type const __len = std::min(__size, __osize); + + int __r = traits_type::compare(_M_begin, __other._M_begin, __len); + if (!__r) + __r = (int)(__size - __osize); + + return __r; + } + + inline bool operator == (pp_string const &__other) const { + return compare(__other) == 0; + } + + inline bool operator != (pp_string const &__other) const { + return compare(__other) != 0; + } + + inline bool operator < (pp_string const &__other) const { + return compare(__other) < 0; + } + + inline bool operator == (char const *s) const { + std::size_t n = strlen(s); + + if (n != _M_size) + return false; + + return ! strncmp(_M_begin, s, n); + } + + inline bool operator != (char const *s) const { + return ! operator == (s); + } +}; + +} // namespace rpp + +#endif // PP_STRING_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp-symbol.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp-symbol.h new file mode 100644 index 000000000..9b06d2643 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp-symbol.h @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** 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 PP_SYMBOL_H +#define PP_SYMBOL_H + +#include <cassert> +#include <iterator> +#include "pp-fwd.h" +#include "parser/rxx_allocator.h" + +namespace rpp +{ + +class pp_symbol +{ + static rxx_allocator<char> &allocator_instance() { + static rxx_allocator<char>__allocator; + return __allocator; + } + static rxx_allocator<pp_fast_string> &ppfs_allocator_instance () + { + static rxx_allocator<pp_fast_string>__ppfs_allocator; + return __ppfs_allocator; + } + +public: + static int &N() { + static int __N; + return __N; + } + + static pp_fast_string const *get(char const *__data, std::size_t __size) { + ++N(); + char *data = allocator_instance().allocate(__size + 1); + memcpy(data, __data, __size); + data[__size] = '\0'; + + pp_fast_string *where = ppfs_allocator_instance ().allocate (sizeof (pp_fast_string)); + return new(where) pp_fast_string(data, __size); + } + + template <typename _InputIterator> + static pp_fast_string const *get(_InputIterator __first, _InputIterator __last) { + ++N(); + std::ptrdiff_t __size; +#if defined(__SUNPRO_CC) + std::distance(__first, __last, __size); +#else + __size = std::distance(__first, __last); +#endif + assert(__size >= 0 && __size < 512); + + char *data = allocator_instance().allocate(__size + 1); + std::copy(__first, __last, data); + data[__size] = '\0'; + + pp_fast_string *where = ppfs_allocator_instance ().allocate (sizeof (pp_fast_string)); + return new(where) pp_fast_string(data, __size); + } + + static pp_fast_string const *get(std::string const &__s) { + return get(__s.c_str(), __s.size()); + } +}; + +} // namespace rpp + +#endif // PP_SYMBOL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/pp.h b/sources/shiboken2/ApiExtractor/parser/rpp/pp.h new file mode 100644 index 000000000..dfeeac432 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/pp.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** 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 PP_H +#define PP_H + +#if defined(_WIN64) || defined(WIN64) || defined(__WIN64__) \ + || defined(_WIN32) || defined(WIN32) || defined(__WIN32__) +# define PP_OS_WIN +#endif + +#include <set> +#include <map> +#include <vector> +#include <string> +#include <iterator> +#include <iostream> +#include <cassert> +#include <cctype> +#include <cstdio> + +#include <fcntl.h> + +#ifdef HAVE_MMAP +# include <sys/mman.h> +#endif + +#include <sys/stat.h> +#include <sys/types.h> + +#if (_MSC_VER >= 1400) +# define FILENO _fileno +#else +# define FILENO fileno +#endif + +#if defined (PP_OS_WIN) +# define PATH_SEPARATOR '\\' +#else +# define PATH_SEPARATOR '/' +#endif + +#if defined (RPP_JAMBI) +# include "parser/rxx_allocator.h" +#else +# include "parser/rpp-allocator.h" +#endif + +#if defined (_MSC_VER) +# define pp_snprintf _snprintf +#else +# define pp_snprintf snprintf +#endif + +#include "pp-fwd.h" +#include "pp-cctype.h" +#include "pp-string.h" +#include "pp-symbol.h" +#include "pp-internal.h" +#include "pp-iterator.h" +#include "pp-macro.h" +#include "pp-environment.h" +#include "pp-scanner.h" +#include "pp-macro-expander.h" +#include "pp-engine.h" +#include "pp-engine-bits.h" + +#endif // PP_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/preprocessor.cpp b/sources/shiboken2/ApiExtractor/parser/rpp/preprocessor.cpp new file mode 100644 index 000000000..315343321 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/preprocessor.cpp @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2005 Harald Fernengel <harry@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 "preprocessor.h" + +#include <string> +#include <cstdio> + +// register callback for include hooks +static void includeFileHook(const std::string &, const std::string &, FILE *); + +#define PP_HOOK_ON_FILE_INCLUDED(A, B, C) includeFileHook(A, B, C) +#include "pp.h" + +using namespace rpp; + +#include <QtCore/QtCore> + +class PreprocessorPrivate +{ +public: + QByteArray result; + pp_environment env; + QStringList includePaths; + + void initPP(pp &proc) { + foreach(QString path, includePaths) + proc.push_include_path(path.toStdString()); + } +}; + +QHash<QString, QStringList> includedFiles; + +void includeFileHook(const std::string &fileName, const std::string &filePath, FILE *) +{ + includedFiles[QString::fromStdString(fileName)].append(QString::fromStdString(filePath)); +} + +Preprocessor::Preprocessor() +{ + d = new PreprocessorPrivate; + includedFiles.clear(); +} + +Preprocessor::~Preprocessor() +{ + delete d; +} + +void Preprocessor::processFile(const QString &fileName) +{ + pp proc(d->env); + d->initPP(proc); + + d->result.reserve(d->result.size() + 20 * 1024); + + d->result += "# 1 \"" + fileName.toLatin1() + "\"\n"; // ### REMOVE ME + proc.file(fileName.toLocal8Bit().constData(), std::back_inserter(d->result)); +} + +void Preprocessor::processString(const QByteArray &str) +{ + pp proc(d->env); + d->initPP(proc); + + proc(str.begin(), str.end(), std::back_inserter(d->result)); +} + +QByteArray Preprocessor::result() const +{ + return d->result; +} + +void Preprocessor::addIncludePaths(const QStringList &includePaths) +{ + d->includePaths += includePaths; +} + +QStringList Preprocessor::macroNames() const +{ + QStringList macros; + + pp_environment::const_iterator it = d->env.first_macro(); + while (it != d->env.last_macro()) { + const pp_macro *m = *it; + macros += QString::fromLatin1(m->name->begin(), m->name->size()); + ++it; + } + + return macros; +} + +QList<Preprocessor::MacroItem> Preprocessor::macros() const +{ + QList<MacroItem> items; + + pp_environment::const_iterator it = d->env.first_macro(); + while (it != d->env.last_macro()) { + const pp_macro *m = *it; + MacroItem item; + item.name = QString::fromLatin1(m->name->begin(), m->name->size()); + item.definition = QString::fromLatin1(m->definition->begin(), + m->definition->size()); + for (size_t i = 0; i < m->formals.size(); ++i) { + item.parameters += QString::fromLatin1(m->formals[i]->begin(), + m->formals[i]->size()); + } + item.isFunctionLike = m->function_like; + +#ifdef PP_WITH_MACRO_POSITION + item.fileName = QString::fromLatin1(m->file->begin(), m->file->size()); +#endif + items += item; + + ++it; + } + + return items; +} + +/* +int main() +{ + Preprocessor pp; + + QStringList paths; + paths << "/usr/include"; + pp.addIncludePaths(paths); + + pp.processFile("pp-configuration"); + pp.processFile("/usr/include/stdio.h"); + + qDebug() << pp.result(); + + return 0; +} +*/ + diff --git a/sources/shiboken2/ApiExtractor/parser/rpp/preprocessor.h b/sources/shiboken2/ApiExtractor/parser/rpp/preprocessor.h new file mode 100644 index 000000000..7d00a5d09 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rpp/preprocessor.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2005 Harald Fernengel <harry@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 PREPROCESSOR_H +#define PREPROCESSOR_H + +#include <QtCore/qglobal.h> +#include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> + +class PreprocessorPrivate; + +class Preprocessor +{ +public: + Preprocessor(); + ~Preprocessor(); + + void processFile(const QString &fileName); + void processString(const QByteArray &str); + + void addIncludePaths(const QStringList &includePaths); + + QByteArray result() const; + + QStringList macroNames() const; + + struct MacroItem { + QString name; + QStringList parameters; + QString definition; + bool isFunctionLike; +#ifdef PP_WITH_MACRO_POSITION + QString fileName; +#endif + }; + QList<MacroItem> macros() const; + +private: + Q_DISABLE_COPY(Preprocessor) + PreprocessorPrivate *d; +}; + +#endif diff --git a/sources/shiboken2/ApiExtractor/parser/rxx_allocator.h b/sources/shiboken2/ApiExtractor/parser/rxx_allocator.h new file mode 100644 index 000000000..8325edbdf --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/rxx_allocator.h @@ -0,0 +1,146 @@ +/* This file is part of KDevelop + Copyright 2002-2005 Roberto Raggi <roberto@kdevelop.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef RXX_ALLOCATOR_H +#define RXX_ALLOCATOR_H + +#include <cstddef> +#include <cstdlib> +#include <string.h> +#include <memory> + +// Stride calculation +template <typename T> +struct Tchar { + T t; + char c; +}; + +#define strideof(T) \ + ((sizeof(Tchar<T>) > sizeof(T)) ? \ + sizeof(Tchar<T>)-sizeof(T) : sizeof(T)) + + +/**The allocator which uses fixed size blocks for allocation of its elements. +Block size is currently 64k, allocated space is not reclaimed, +if the size of the element being allocated extends the amount of free +memory in the block then a new block is allocated. + +The allocator supports standard c++ library interface but does not +make use of allocation hints. +*/ +template <class _Tp> class rxx_allocator { +public: + typedef _Tp value_type; + typedef _Tp* pointer; + typedef const _Tp* const_pointer; + typedef _Tp& reference; + typedef const _Tp& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + static const size_type max_block_count = size_type(-1); + static const size_type _S_block_size = 1 << 16; // 64K + + rxx_allocator() { + init(); + } + + rxx_allocator(const rxx_allocator &/*__o*/) { + init(); + } + + ~rxx_allocator() { + for (size_type index = 0; index < _M_block_index + 1; ++index) + delete[] _M_storage[index]; + + ::free(_M_storage); + } + + pointer address(reference __val) { return &__val; } + const_pointer address(const_reference __val) const { return &__val; } + + /**Allocates @p __n elements continuosly in the pool. Warning! no + check is done to check if the size of those @p __n elements + fit into the block. You should assure you do not allocate more + than the size of a block.*/ + pointer allocate(size_type __n, const void* = 0) { + const size_type bytes = __n * sizeof(_Tp); + + if (_M_current_block == 0 + || _S_block_size < _M_current_index + bytes) + { + ++_M_block_index; + + _M_storage = reinterpret_cast<char**> + (::realloc(_M_storage, sizeof(char*) * (1 + _M_block_index))); + + _M_current_block = _M_storage[_M_block_index] = reinterpret_cast<char*> + (new char[_S_block_size]); + + ::memset(_M_current_block, 0, _S_block_size); + _M_current_index = 0; + } + + pointer p = reinterpret_cast<pointer> + (_M_current_block + _M_current_index); + + _M_current_index += bytes; + + return p; + } + + pointer allocate(size_type __n, size_type stride, const void* = 0) { + if (reinterpret_cast<size_type>(_M_current_block + _M_current_index) % stride > 0) + _M_current_index += stride - reinterpret_cast<size_type>(_M_current_block + _M_current_index) % stride; + return allocate(__n); + } + + /**Deallocate does nothing in this implementation.*/ + void deallocate(pointer /*__p*/, size_type /*__n*/) {} + + size_type max_size() const { return size_type(-1) / sizeof(_Tp); } + + void construct(pointer __p, const_reference __val) { new (__p) _Tp(__val); } + void destroy(pointer __p) { __p->~_Tp(); } + + template <class _Tp1> struct rebind { + typedef rxx_allocator<_Tp1> other; + }; + +private: + + void init() + { + _M_block_index = max_block_count; + _M_current_index = 0; + _M_storage = 0; + _M_current_block = 0; + } + + template <class _Tp1> rxx_allocator(const rxx_allocator<_Tp1> &__o) {} + +private: + size_type _M_block_index; + size_type _M_current_index; + char *_M_current_block; + char **_M_storage; +}; + +#endif // RXX_ALLOCATOR_H + diff --git a/sources/shiboken2/ApiExtractor/parser/smallobject.cpp b/sources/shiboken2/ApiExtractor/parser/smallobject.cpp new file mode 100644 index 000000000..9cee247e0 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/smallobject.cpp @@ -0,0 +1,33 @@ +/**************************************************************************** +** +** 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 "smallobject.h" + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/smallobject.h b/sources/shiboken2/ApiExtractor/parser/smallobject.h new file mode 100644 index 000000000..99e4ea44a --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/smallobject.h @@ -0,0 +1,58 @@ +/**************************************************************************** +** +** 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 SMALLOBJECT_H +#define SMALLOBJECT_H + +#include "rxx_allocator.h" +#include <cstring> + +class pool +{ + rxx_allocator<char> __alloc; + +public: + inline void *allocate(std::size_t __size); + inline void *allocate(std::size_t __size, std::size_t __stride); +}; + +inline void *pool::allocate(std::size_t __size) +{ + return __alloc.allocate(__size); +} + +inline void *pool::allocate(std::size_t __size, std::size_t __stride) +{ + return __alloc.allocate(__size, __stride); +} + +#endif + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/symbol.h b/sources/shiboken2/ApiExtractor/parser/symbol.h new file mode 100644 index 000000000..588653846 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/symbol.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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 SYMBOL_H +#define SYMBOL_H + +#include <QtCore/QString> +#include <cstring> + +#include <QtCore/QHash> +#include <QtCore/QPair> + +struct NameSymbol +{ + const char *data; + std::size_t count; + + inline QString as_string() const + { + return QString::fromUtf8(data, (int) count); + } + + inline bool operator == (const NameSymbol &other) const + { + return count == other.count + && !std::strncmp(data, other.data, count); + } + +protected: + inline NameSymbol() {} + inline NameSymbol(const char *d, std::size_t c) + : data(d), count(c) {} + +private: + void operator = (const NameSymbol &); + + friend class NameTable; +}; + +inline uint qHash(const NameSymbol &r) +{ + uint hash_value = 0; + + for (std::size_t i = 0; i < r.count; ++i) + hash_value = (hash_value << 5) - hash_value + r.data[i]; + + return hash_value; +} + +inline uint qHash(const QPair<const char*, std::size_t> &r) +{ + uint hash_value = 0; + + for (std::size_t i = 0; i < r.second; ++i) + hash_value = (hash_value << 5) - hash_value + r.first[i]; + + return hash_value; +} + +class NameTable +{ +public: + typedef QPair<const char *, std::size_t> KeyType; + typedef QHash<KeyType, NameSymbol*> ContainerType; + +public: + NameTable() {} + + ~NameTable() + { + qDeleteAll(_M_storage); + } + + inline const NameSymbol *findOrInsert(const char *str, std::size_t len) + { + KeyType key(str, len); + + NameSymbol *name = _M_storage.value(key); + if (!name) { + name = new NameSymbol(str, len); + _M_storage.insert(key, name); + } + + return name; + } + + inline std::size_t count() const { return _M_storage.size(); } + +private: + ContainerType _M_storage; + +private: + NameTable(const NameTable &other); + void operator=(const NameTable &other); +}; + +#endif // SYMBOL_H + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/sources/shiboken2/ApiExtractor/parser/tokens.cpp b/sources/shiboken2/ApiExtractor/parser/tokens.cpp new file mode 100644 index 000000000..eace3c9fa --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/tokens.cpp @@ -0,0 +1,256 @@ +/**************************************************************************** +** +** 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 <QtCore/qglobal.h> + +#include "tokens.h" + +static char const * const _S_token_names[] = { + "K_DCOP", + "Q_OBJECT", + "Q_PROPERTY", + "__attribute__", + "__typeof", + "and", + "and_eq", + "arrow", + "asm", + "assign", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char_literal", + "class", + "comment", + "compl", + "concat", + "const", + "const_cast", + "continue", + "decr", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "ellipsis", + "else", + "emit", + "enum", + "eq", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "geq", + "goto", + "identifier", + "if", + "incr", + "inline", + "int", + "k_dcop", + "k_dcop_signals", + "leq", + "long", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "number_literal", + "operator", + "or", + "or_eq", + "preproc", + "private", + "protected", + "ptrmem", + "public", + "register", + "reinterpret_cast", + "return", + "scope", + "shift", + "short", + "signals", + "signed", + "sizeof", + "slots", + "static", + "static_cast", + "string_literal", + "struct", + "switch", + "template", + "this", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "whitespaces", + "xor", + "xor_eq", + "Q_ENUMS", + "Q_ENUM" +}; + +static char _S_printable[][2] = { + { char(32), '\0' }, + { char(33), '\0' }, + { char(34), '\0' }, + { char(35), '\0' }, + { char(36), '\0' }, + { char(37), '\0' }, + { char(38), '\0' }, + { char(39), '\0' }, + { char(40), '\0' }, + { char(41), '\0' }, + { char(42), '\0' }, + { char(43), '\0' }, + { char(44), '\0' }, + { char(45), '\0' }, + { char(46), '\0' }, + { char(47), '\0' }, + { char(48), '\0' }, + { char(49), '\0' }, + { char(50), '\0' }, + { char(51), '\0' }, + { char(52), '\0' }, + { char(53), '\0' }, + { char(54), '\0' }, + { char(55), '\0' }, + { char(56), '\0' }, + { char(57), '\0' }, + { char(58), '\0' }, + { char(59), '\0' }, + { char(60), '\0' }, + { char(61), '\0' }, + { char(62), '\0' }, + { char(63), '\0' }, + { char(64), '\0' }, + { char(65), '\0' }, + { char(66), '\0' }, + { char(67), '\0' }, + { char(68), '\0' }, + { char(69), '\0' }, + { char(70), '\0' }, + { char(71), '\0' }, + { char(72), '\0' }, + { char(73), '\0' }, + { char(74), '\0' }, + { char(75), '\0' }, + { char(76), '\0' }, + { char(77), '\0' }, + { char(78), '\0' }, + { char(79), '\0' }, + { char(80), '\0' }, + { char(81), '\0' }, + { char(82), '\0' }, + { char(83), '\0' }, + { char(84), '\0' }, + { char(85), '\0' }, + { char(86), '\0' }, + { char(87), '\0' }, + { char(88), '\0' }, + { char(89), '\0' }, + { char(90), '\0' }, + { char(91), '\0' }, + { char(92), '\0' }, + { char(93), '\0' }, + { char(94), '\0' }, + { char(95), '\0' }, + { char(96), '\0' }, + { char(97), '\0' }, + { char(98), '\0' }, + { char(99), '\0' }, + { char(100), '\0' }, + { char(101), '\0' }, + { char(102), '\0' }, + { char(103), '\0' }, + { char(104), '\0' }, + { char(105), '\0' }, + { char(106), '\0' }, + { char(107), '\0' }, + { char(108), '\0' }, + { char(109), '\0' }, + { char(110), '\0' }, + { char(111), '\0' }, + { char(112), '\0' }, + { char(113), '\0' }, + { char(114), '\0' }, + { char(115), '\0' }, + { char(116), '\0' }, + { char(117), '\0' }, + { char(118), '\0' }, + { char(119), '\0' }, + { char(120), '\0' }, + { char(121), '\0' }, + { char(122), '\0' }, + { char(123), '\0' }, + { char(124), '\0' }, + { char(125), '\0' }, + { char(126), '\0' }, + { char(127), '\0' }, +}; + +char const *token_name(int token) +{ + if (token == 0) + return "eof"; + else if (token >= 32 && token <= 127) + return _S_printable[token - 32]; + else if (token >= 1000) + return _S_token_names[token - 1000]; + + Q_ASSERT(0); + return 0; +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/tokens.h b/sources/shiboken2/ApiExtractor/parser/tokens.h new file mode 100644 index 000000000..46ec96e74 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/tokens.h @@ -0,0 +1,152 @@ +/**************************************************************************** +** +** 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 TOKENS_H +#define TOKENS_H + +enum TOKEN_KIND { + Token_EOF = 0, + + Token_K_DCOP = 1000, + Token_Q_OBJECT, + Token_Q_PROPERTY, + Token___attribute__, + Token___typeof, + Token_and, + Token_and_eq, + Token_arrow, + Token_asm, + Token_assign, + Token_auto, + Token_bitand, + Token_bitor, + Token_bool, + Token_break, + Token_case, + Token_catch, + Token_char, + Token_char_literal, + Token_class, + Token_comment, + Token_compl, + Token_concat, + Token_const, + Token_const_cast, + Token_continue, + Token_decr, + Token_default, + Token_delete, + Token_do, + Token_double, + Token_dynamic_cast, + Token_ellipsis, + Token_else, + Token_emit, + Token_enum, + Token_eq, + Token_explicit, + Token_export, + Token_extern, + Token_false, + Token_float, + Token_for, + Token_friend, + Token_geq, + Token_goto, + Token_identifier, + Token_if, + Token_incr, + Token_inline, + Token_int, + Token_k_dcop, + Token_k_dcop_signals, + Token_leq, + Token_long, + Token_mutable, + Token_namespace, + Token_new, + Token_noexcept, + Token_not, + Token_not_eq, + Token_number_literal, + Token_operator, + Token_or, + Token_or_eq, + Token_preproc, + Token_private, + Token_protected, + Token_ptrmem, + Token_public, + Token_register, + Token_reinterpret_cast, + Token_return, + Token_scope, + Token_shift, + Token_short, + Token_signals, + Token_signed, + Token_sizeof, + Token_slots, + Token_static, + Token_static_cast, + Token_string_literal, + Token_struct, + Token_switch, + Token_template, + Token_this, + Token_throw, + Token_true, + Token_try, + Token_typedef, + Token_typeid, + Token_typename, + Token_union, + Token_unsigned, + Token_using, + Token_virtual, + Token_void, + Token_volatile, + Token_wchar_t, + Token_while, + Token_whitespaces, + Token_xor, + Token_xor_eq, + Token_Q_ENUMS, + Token_Q_ENUM, + Token_Q_INVOKABLE, + + TOKEN_KIND_COUNT +}; + +char const *token_name(int token); + +#endif + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/type_compiler.cpp b/sources/shiboken2/ApiExtractor/parser/type_compiler.cpp new file mode 100644 index 000000000..c08f210fa --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/type_compiler.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ + + +#include "type_compiler.h" +#include "name_compiler.h" +#include "lexer.h" +#include "symbol.h" +#include "tokens.h" +#include "binder.h" + +#include <QtCore/QString> + +TypeCompiler::TypeCompiler(Binder *binder) + : _M_binder(binder), _M_token_stream(binder->tokenStream()) +{ +} + +void TypeCompiler::run(TypeSpecifierAST *node) +{ + _M_type.clear(); + _M_cv.clear(); + + visit(node); + + if (node && node->cv) { + const ListNode<std::size_t> *it = node->cv->toFront(); + const ListNode<std::size_t> *end = it; + do { + int kind = _M_token_stream->kind(it->element); + if (!_M_cv.contains(kind)) + _M_cv.append(kind); + + it = it->next; + } while (it != end); + } +} + +void TypeCompiler::visitClassSpecifier(ClassSpecifierAST *node) +{ + visit(node->name); +} + +void TypeCompiler::visitEnumSpecifier(EnumSpecifierAST *node) +{ + visit(node->name); +} + +void TypeCompiler::visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node) +{ + visit(node->name); +} + +void TypeCompiler::visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node) +{ + if (const ListNode<std::size_t> *it = node->integrals) { + it = it->toFront(); + const ListNode<std::size_t> *end = it; + QString current_item; + do { + std::size_t token = it->element; + current_item += QLatin1String(token_name(_M_token_stream->kind(token))); + current_item += QLatin1Char(' '); + it = it->next; + } while (it != end); + _M_type += current_item.trimmed(); + } else if (node->type_of) { + // ### implement me + _M_type += QLatin1String("typeof<...>"); + } + + visit(node->name); +} + +void TypeCompiler::visitName(NameAST *node) +{ + NameCompiler name_cc(_M_binder); + name_cc.run(node); + _M_type = name_cc.qualifiedName(); +} + +QStringList TypeCompiler::cvString() const +{ + QStringList lst; + + foreach (int q, cv()) { + if (q == Token_const) + lst.append(QLatin1String("const")); + else if (q == Token_volatile) + lst.append(QLatin1String("volatile")); + } + + return lst; +} + +bool TypeCompiler::isConstant() const +{ + return _M_cv.contains(Token_const); +} + +bool TypeCompiler::isVolatile() const +{ + return _M_cv.contains(Token_volatile); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/type_compiler.h b/sources/shiboken2/ApiExtractor/parser/type_compiler.h new file mode 100644 index 000000000..6755b30c3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/type_compiler.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** 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 TYPE_COMPILER_H +#define TYPE_COMPILER_H + +#include "default_visitor.h" + +#include <QtCore/QString> +#include <QtCore/QStringList> +#include <QtCore/QList> + +class TokenStream; +class Binder; + +class TypeCompiler: protected DefaultVisitor +{ +public: + TypeCompiler(Binder *binder); + + inline QStringList qualifiedName() const { return _M_type; } + inline QList<int> cv() const { return _M_cv; } + + bool isConstant() const; + bool isVolatile() const; + + QStringList cvString() const; + + void run(TypeSpecifierAST *node); + +protected: + virtual void visitClassSpecifier(ClassSpecifierAST *node); + virtual void visitEnumSpecifier(EnumSpecifierAST *node); + virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *node); + virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *node); + + virtual void visitName(NameAST *node); + +private: + Binder *_M_binder; + TokenStream *_M_token_stream; + QStringList _M_type; + QList<int> _M_cv; +}; + +#endif // TYPE_COMPILER_H + +// kate: space-indent on; indent-width 2; replace-tabs on; + diff --git a/sources/shiboken2/ApiExtractor/parser/visitor.cpp b/sources/shiboken2/ApiExtractor/parser/visitor.cpp new file mode 100644 index 000000000..e13e4acb3 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/visitor.cpp @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** 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 "visitor.h" + +Visitor::visitor_fun_ptr Visitor::_S_table[AST::NODE_KIND_COUNT] = { + 0, + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitAccessSpecifier), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitAsmDefinition), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitBaseClause), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitBaseSpecifier), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitBinaryExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCastExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitClassMemberAccess), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitClassSpecifier), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCompoundStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCondition), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitConditionalExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCppCastExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitCtorInitializer), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitDeclarationStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitDeclarator), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitDeleteExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitDoStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitElaboratedTypeSpecifier), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitEnumSpecifier), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitEnumerator), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitExceptionSpecification), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitExpressionOrDeclarationStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitExpressionStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitForStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitFunctionCall), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitFunctionDefinition), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitIfStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitIncrDecrExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitInitDeclarator), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitInitializer), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitInitializerClause), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitLabeledStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitLinkageBody), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitLinkageSpecification), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitMemInitializer), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitName), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNamespace), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNamespaceAliasDefinition), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNewDeclarator), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNewExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNewInitializer), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitNewTypeId), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitOperator), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitOperatorFunctionId), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitParameterDeclaration), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitParameterDeclarationClause), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitPostfixExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitPrimaryExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitPtrOperator), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitPtrToMember), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitReturnStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSimpleDeclaration), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSimpleTypeSpecifier), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSizeofExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitStringLiteral), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSubscriptExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitSwitchStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTemplateArgument), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTemplateDeclaration), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTemplateParameter), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitThrowExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTranslationUnit), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTryBlockStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTypeId), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTypeIdentification), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTypeParameter), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitTypedef), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUnaryExpression), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUnqualifiedName), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUsing), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitUsingDirective), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitWhileStatement), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitWinDeclSpec), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitQProperty), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitForwardDeclarationSpecifier), + reinterpret_cast<Visitor::visitor_fun_ptr>(&Visitor::visitQEnums) +}; + +Visitor::Visitor() +{ +} + +Visitor::~Visitor() +{ +} + +void Visitor::visit(AST *node) +{ + if (node) + (this->*_S_table[node->kind])(node); +} + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/parser/visitor.h b/sources/shiboken2/ApiExtractor/parser/visitor.h new file mode 100644 index 000000000..b1fbf8763 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/parser/visitor.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** 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 VISITOR_H +#define VISITOR_H + +#include "ast.h" + +class Visitor +{ +public: + Visitor(); + virtual ~Visitor(); + + virtual void visit(AST *node); + +protected: + virtual void visitAccessSpecifier(AccessSpecifierAST *) {} + virtual void visitAsmDefinition(AsmDefinitionAST *) {} + virtual void visitBaseClause(BaseClauseAST *) {} + virtual void visitBaseSpecifier(BaseSpecifierAST *) {} + virtual void visitBinaryExpression(BinaryExpressionAST *) {} + virtual void visitCastExpression(CastExpressionAST *) {} + virtual void visitClassMemberAccess(ClassMemberAccessAST *) {} + virtual void visitClassSpecifier(ClassSpecifierAST *) {} + virtual void visitCompoundStatement(CompoundStatementAST *) {} + virtual void visitCondition(ConditionAST *) {} + virtual void visitConditionalExpression(ConditionalExpressionAST *) {} + virtual void visitCppCastExpression(CppCastExpressionAST *) {} + virtual void visitCtorInitializer(CtorInitializerAST *) {} + virtual void visitDeclarationStatement(DeclarationStatementAST *) {} + virtual void visitDeclarator(DeclaratorAST *) {} + virtual void visitDeleteExpression(DeleteExpressionAST *) {} + virtual void visitDoStatement(DoStatementAST *) {} + virtual void visitElaboratedTypeSpecifier(ElaboratedTypeSpecifierAST *) {} + virtual void visitEnumSpecifier(EnumSpecifierAST *) {} + virtual void visitEnumerator(EnumeratorAST *) {} + virtual void visitExceptionSpecification(ExceptionSpecificationAST *) {} + virtual void visitExpressionOrDeclarationStatement(ExpressionOrDeclarationStatementAST *) {} + virtual void visitExpressionStatement(ExpressionStatementAST *) {} + virtual void visitForStatement(ForStatementAST *) {} + virtual void visitFunctionCall(FunctionCallAST *) {} + virtual void visitFunctionDefinition(FunctionDefinitionAST *) {} + virtual void visitIfStatement(IfStatementAST *) {} + virtual void visitIncrDecrExpression(IncrDecrExpressionAST *) {} + virtual void visitInitDeclarator(InitDeclaratorAST *) {} + virtual void visitInitializer(InitializerAST *) {} + virtual void visitInitializerClause(InitializerClauseAST *) {} + virtual void visitLabeledStatement(LabeledStatementAST *) {} + virtual void visitLinkageBody(LinkageBodyAST *) {} + virtual void visitLinkageSpecification(LinkageSpecificationAST *) {} + virtual void visitMemInitializer(MemInitializerAST *) {} + virtual void visitName(NameAST *) {} + virtual void visitNamespace(NamespaceAST *) {} + virtual void visitNamespaceAliasDefinition(NamespaceAliasDefinitionAST *) {} + virtual void visitNewDeclarator(NewDeclaratorAST *) {} + virtual void visitNewExpression(NewExpressionAST *) {} + virtual void visitNewInitializer(NewInitializerAST *) {} + virtual void visitNewTypeId(NewTypeIdAST *) {} + virtual void visitOperator(OperatorAST *) {} + virtual void visitOperatorFunctionId(OperatorFunctionIdAST *) {} + virtual void visitParameterDeclaration(ParameterDeclarationAST *) {} + virtual void visitParameterDeclarationClause(ParameterDeclarationClauseAST *) {} + virtual void visitPostfixExpression(PostfixExpressionAST *) {} + virtual void visitPrimaryExpression(PrimaryExpressionAST *) {} + virtual void visitPtrOperator(PtrOperatorAST *) {} + virtual void visitPtrToMember(PtrToMemberAST *) {} + virtual void visitReturnStatement(ReturnStatementAST *) {} + virtual void visitSimpleDeclaration(SimpleDeclarationAST *) {} + virtual void visitSimpleTypeSpecifier(SimpleTypeSpecifierAST *) {} + virtual void visitSizeofExpression(SizeofExpressionAST *) {} + virtual void visitStringLiteral(StringLiteralAST *) {} + virtual void visitSubscriptExpression(SubscriptExpressionAST *) {} + virtual void visitSwitchStatement(SwitchStatementAST *) {} + virtual void visitTemplateArgument(TemplateArgumentAST *) {} + virtual void visitTemplateDeclaration(TemplateDeclarationAST *) {} + virtual void visitTemplateParameter(TemplateParameterAST *) {} + virtual void visitThrowExpression(ThrowExpressionAST *) {} + virtual void visitTranslationUnit(TranslationUnitAST *) {} + virtual void visitTryBlockStatement(TryBlockStatementAST *) {} + virtual void visitTypeId(TypeIdAST *) {} + virtual void visitTypeIdentification(TypeIdentificationAST *) {} + virtual void visitTypeParameter(TypeParameterAST *) {} + virtual void visitTypedef(TypedefAST *) {} + virtual void visitUnaryExpression(UnaryExpressionAST *) {} + virtual void visitUnqualifiedName(UnqualifiedNameAST *) {} + virtual void visitUsing(UsingAST *) {} + virtual void visitUsingDirective(UsingDirectiveAST *) {} + virtual void visitWhileStatement(WhileStatementAST *) {} + virtual void visitWinDeclSpec(WinDeclSpecAST *) {} + virtual void visitQProperty(QPropertyAST *) {} + virtual void visitForwardDeclarationSpecifier(ForwardDeclarationSpecifierAST *) {} + virtual void visitQEnums(QEnumsAST *) {} + +private: + typedef void (Visitor::*visitor_fun_ptr)(AST *); + static visitor_fun_ptr _S_table[]; +}; + +template <class _Tp> +void visitNodes(Visitor *v, const ListNode<_Tp> *nodes) +{ + if (!nodes) + return; + + const ListNode<_Tp> + *it = nodes->toFront(), + *end = it; + + do { + v->visit(it->element); + it = it->next; + } while (it != end); +} + +#endif // VISITOR_H + +// kate: space-indent on; indent-width 2; replace-tabs on; diff --git a/sources/shiboken2/ApiExtractor/qtdocparser.cpp b/sources/shiboken2/ApiExtractor/qtdocparser.cpp new file mode 100644 index 000000000..f1421ff91 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/qtdocparser.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** 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; + foreach (DocModification docModif, metaClass->typeEntry()->docModifications()) { + if (docModif.signature().isEmpty()) + classModifs.append(docModif); + else + signedModifs.append(docModif); + } + + Documentation doc(getDocumentation(xquery, query, classModifs)); + metaClass->setDocumentation(doc); + + + //Functions Documentation + AbstractMetaFunctionList funcs = metaClass->functionsInTargetLang(); + foreach (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("\"]"); + + int i = 1; + foreach (AbstractMetaArgument* arg, func->arguments()) { + 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) + + QLatin1String("][@left=\"") + type + QLatin1String("\"]/.."); + ++i; + } + } + query += QLatin1String("/description"); + DocModificationList funcModifs; + foreach (DocModification funcModif, signedModifs) { + if (funcModif.signature() == func->minimalSignature()) + funcModifs.append(funcModif); + } + doc.setValue(getDocumentation(xquery, query, funcModifs)); + func->setDocumentation(doc); + } +#if 0 + // Fields + AbstractMetaFieldList fields = metaClass->fields(); + foreach (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 + AbstractMetaEnumList enums = metaClass->enums(); + foreach (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..04c491853 --- /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() {} + virtual void fillDocumentation(AbstractMetaClass* metaClass); + virtual Documentation retrieveModuleDocumentation(); + virtual Documentation retrieveModuleDocumentation(const QString& name); +}; + +#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..5429c1cb8 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/CMakeLists.txt @@ -0,0 +1,73 @@ +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} + ) + 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..028522159 --- /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")) + classes.swap(0, 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()")) + ctors.swap(0, 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()")) + ctors.swap(0, 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)")) + ctors.swap(0, 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()")) + ctors.swap(0, 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<B>)'/>\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..6e1da17ae --- /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_")); + QList< 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&)' 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()); + AbstractMetaFunctionList lst = foo->queryFunctions(AbstractMetaClass::Constructors); + foreach(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<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..5385c9140 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testarrayargument.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** +** +** 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; + foreach (AbstractMetaEnumValue* enumValue, someEnum->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..cae4a3a62 --- /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; + foreach(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..6700239d6 --- /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..94158377e --- /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); + + QList<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); + + QList<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..4438550b2 --- /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&)'>\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&)'/>\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; + foreach(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\ + <para>Some changed contents here</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..0e6bdc248 --- /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); + QList<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..67c9089ce --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testmultipleinheritance.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** 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; + foreach (AbstractMetaFunction* f, classD->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&)' 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..6b27227d6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testremoveoperatormethod.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** 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>>(char&)' remove='all'/>\n\ + <modify-function signature='operator>>(char*)' remove='all'/>\n\ + <modify-function signature='operator>>(short&)' remove='all'/>\n\ + <modify-function signature='operator>>(unsigned short&)' remove='all'/>\n\ + <modify-function signature='operator>>(int&)' remove='all'/>\n\ + <modify-function signature='operator>>(unsigned int&)' remove='all'/>\n\ + <modify-function signature='operator>>(int64_t&)' remove='all'/>\n\ + <modify-function signature='operator>>(uint64_t&)' remove='all'/>\n\ + <modify-function signature='operator>>(float&)' remove='all'/>\n\ + <modify-function signature='operator>>(double&)' remove='all'/>\n\ + <modify-function signature='operator>>(Char&)' remove='all'/>\n\ + <modify-function signature='operator>>(String&)' 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(); + foreach (const AbstractMetaFunction* f, classA->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..76ba7d3b4 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testreverseoperators.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** 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; + foreach(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)); + 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; + foreach(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..cb90383db --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp @@ -0,0 +1,438 @@ +/**************************************************************************** +** +** 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<int>)'/>\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<int>*)'/>\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<int>&)'/>\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); + 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..d4eb2fdf6 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testutil.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** 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 "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 + buffer.setData(cppCode); + AbstractMetaBuilder *builder = new AbstractMetaBuilder; + if (!builder->build(&buffer)) { + 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..55170d7c1 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typedatabase.cpp @@ -0,0 +1,699 @@ +/**************************************************************************** +** +** 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/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 +{ + QList<TypeEntry *> entries = findTypes(name); + foreach (TypeEntry *entry, entries) { + if (entry && + (!entry->isPrimitive() || static_cast<PrimitiveTypeEntry *>(entry)->preferredTargetLangType())) { + return entry; + } + } + return 0; +} + +QList<TypeEntry *> 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; +} + +QList<const PrimitiveTypeEntry*> TypeDatabase::primitiveTypes() const +{ + TypeEntryHash entries = allEntries(); + QList<const PrimitiveTypeEntry*> returned; + for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) { + foreach (TypeEntry *typeEntry, it.value()) { + if (typeEntry->isPrimitive()) + returned.append(static_cast<PrimitiveTypeEntry *>(typeEntry)); + } + } + return returned; +} + +QList<const ContainerTypeEntry*> TypeDatabase::containerTypes() const +{ + TypeEntryHash entries = allEntries(); + QList<const ContainerTypeEntry*> returned; + for (TypeEntryHash::const_iterator it = entries.cbegin(), end = entries.cend(); it != end; ++it) { + foreach (TypeEntry *typeEntry, it.value()) { + if (typeEntry->isContainer()) + returned.append(static_cast<ContainerTypeEntry *>(typeEntry)); + } + } + return returned; +} +void TypeDatabase::addRejection(const QString& className, const QString& functionName, + const QString& fieldName, const QString& enumName) +{ + TypeRejection r; + r.class_name = className; + r.function_name = functionName; + r.field_name = fieldName; + r.enum_name = enumName; + + m_rejections << r; +} + +bool TypeDatabase::isClassRejected(const QString& className) const +{ + foreach (const TypeRejection& r, m_rejections) { + if (r.class_name == className && r.function_name == QLatin1String("*") + && r.field_name == QLatin1String("*") && r.enum_name == QLatin1String("*")) { + return true; + } + } + return false; +} + +bool TypeDatabase::isEnumRejected(const QString& className, const QString& enumName) const +{ + foreach (const TypeRejection& r, m_rejections) { + if (r.enum_name == enumName + && (r.class_name == className || r.class_name == QLatin1String("*"))) { + return true; + } + } + + return false; +} + +void TypeDatabase::addType(TypeEntry *e) +{ + m_entries[e->qualifiedCppName()].append(e); +} + +bool TypeDatabase::isFunctionRejected(const QString& className, const QString& functionName) const +{ + foreach (const TypeRejection& r, m_rejections) + if (r.function_name == functionName && + (r.class_name == className || r.class_name == QLatin1String("*"))) + return true; + return false; +} + + +bool TypeDatabase::isFieldRejected(const QString& className, const QString& fieldName) const +{ + foreach (const TypeRejection& r, m_rejections) + if (r.field_name == fieldName && + (r.class_name == className || r.class_name == QLatin1String("*"))) + return true; + return false; +} + +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; + foreach (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; + + foreach (const QString &_warning, m_suppressedWarnings) { + QString warning = _warning; + 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(); + foreach (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 +{ + QList<TypeEntry*> entries = findTypes(name); + + foreach (TypeEntry* entry, entries) { + if (entry && entry->isPrimitive() && static_cast<PrimitiveTypeEntry*>(entry)->preferredTargetLangType()) + return static_cast<PrimitiveTypeEntry*>(entry); + } + + return 0; +} + +ComplexTypeEntry* TypeDatabase::findComplexType(const QString& name) const +{ + QList<TypeEntry*> entries = findTypes(name); + foreach (TypeEntry* entry, entries) { + if (entry && entry->isComplex()) + return static_cast<ComplexTypeEntry*>(entry); + } + return 0; +} + +ObjectTypeEntry* TypeDatabase::findObjectType(const QString& name) const +{ + QList<TypeEntry*> entries = findTypes(name); + foreach (TypeEntry* entry, entries) { + if (entry && entry->isObject()) + return static_cast<ObjectTypeEntry*>(entry); + } + return 0; +} + +NamespaceTypeEntry* TypeDatabase::findNamespaceType(const QString& name) const +{ + QList<TypeEntry*> entries = findTypes(name); + foreach (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, QList<TypeEntry*> > GroupedTypeEntries; + GroupedTypeEntries groupedEntries; + + // Group type entries by revision numbers + TypeEntryHash allEntries = tdb->allEntries(); + foreach (QList<TypeEntry*> entryList, allEntries) { + foreach (TypeEntry* entry, entryList) { + 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 + QList<TypeEntry*>::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); + + foreach (TypeEntry* entry, 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..4255cf458 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typedatabase.h @@ -0,0 +1,179 @@ +/**************************************************************************** +** +** 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 "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; + + QList<const PrimitiveTypeEntry*> primitiveTypes() const; + + QList<const ContainerTypeEntry*> containerTypes() const; + + void addRejection(const QString& className, const QString& functionName, + const QString& fieldName, const QString& enumName); + bool isClassRejected(const QString& className) const; + bool isFunctionRejected(const QString& className, const QString& functionName) const; + bool isFieldRejected(const QString& className, const QString& fieldName) const; + bool isEnumRejected(const QString& className, const QString& enumName) const; + + void addType(TypeEntry* e); + + 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: + QList<TypeEntry *> 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; + + QList<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/typeparser.cpp b/sources/shiboken2/ApiExtractor/typeparser.cpp new file mode 100644 index 000000000..67120a1ac --- /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; + foreach (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..9ccd0992c --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typeparser.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** 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> + +class TypeParser +{ +public: + struct Info + { + Info() : referenceType(NoReference), is_constant(false), is_busted(false), indirections(0) { } + QStringList qualified_name; + QStringList arrays; + QList<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..869904d43 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typesystem.cpp @@ -0,0 +1,2667 @@ +/**************************************************************************** +** +** 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/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 QList<CustomConversion*> customConversionsForReview = QList<CustomConversion*>(); + +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); + foreach (CustomConversion* customConversion, customConversionsForReview) { + foreach (CustomConversion::TargetToNativeConversion* toNative, customConversion->targetToNativeConversions()) + 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 QRegExp whiteSpace(QLatin1String("\\s")); + 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 QRegExp functionNameRegExp(QLatin1String("^[a-zA-Z_][a-zA-Z0-9_]*$")); + if (!functionNameRegExp.exactMatch(rename)) { + 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()) { + foreach (const QString &flagName, flagNames.split(QLatin1Char(','))) + 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(QLatin1String("class"), QLatin1String("*")); + attributes.insert(QLatin1String("function-name"), QLatin1String("*")); + attributes.insert(QLatin1String("field-name"), QLatin1String("*")); + attributes.insert(QLatin1String("enum-name"), QLatin1String("*")); + 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:"); + foreach (const QString &action, actions.keys()) + m_error += QLatin1Char(' ') + action; + } + + 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: { + QString cls = attributes[QLatin1String("class")]; + QString function = attributes[QLatin1String("function-name")]; + QString field = attributes[QLatin1String("field-name")]; + QString enum_ = attributes[QLatin1String("enum-name")]; + if (cls == QLatin1String("*") && function == QLatin1String("*") && field == QLatin1String("*") && enum_ == QLatin1String("*")) { + m_error = QLatin1String("bad reject entry, neither 'class', 'function-name' nor " + "'field' specified"); + return false; + } + m_database->addRejection(cls, function, field, enum_); + } + break; + case StackElement::Template: + element->value.templateEntry = new TemplateEntry(attributes[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; + foreach (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) { + foreach (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; + QRegExp regex(QLatin1String("\\w")); + 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() +{ + foreach (TargetToNativeConversion* targetToNativeConversion, m_d->targetToNativeConversions) + delete targetToNativeConversion; + m_d->targetToNativeConversions.clear(); + 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..a8ee0ced4 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typesystem.h @@ -0,0 +1,1947 @@ +/**************************************************************************** +** +** 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/QString> +#include <QtCore/QStringList> +#include <QtCore/QMap> + +//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 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(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)); + } + + QList<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(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(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 + QList<ReferenceCount> referenceCounts; + + // The text given for the new type of the argument + QString modified_type; + + QString replace_value; + + // The code to be used to construct a return value when 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(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; + + QList<ArgumentModification> argument_mods; + +private: + FunctionModification() {} + + 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); + + /// 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. + QList<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; + QList<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(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) + { + 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 + { + return m_nestedType->targetLangName() + QLatin1String("[]"); + } + QString targetLangApiName() const + { + 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 + { + return m_targetLangName; + } + void setTargetLangName(const QString &targetLangName) + { + m_targetLangName = targetLangName; + } + + QString targetLangApiName() const + { + 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; + + virtual bool preferredConversion() const + { + return m_preferredConversion; + } + virtual void setPreferredConversion(bool b) + { + m_preferredConversion = b; + } + + virtual bool preferredTargetLangType() const + { + return m_preferredTargetLangType; + } + virtual void setPreferredTargetLangType(bool b) + { + m_preferredTargetLangType = b; + } + + void setTargetLangPackage(const QString& package); + QString targetLangPackage() const; +private: + QString m_targetLangName; + QString m_targetLangApiName; + QString m_defaultConstructor; + uint m_preferredConversion : 1; + uint m_preferredTargetLangType : 1; + PrimitiveTypeEntry* m_referencedTypeEntry; +}; + +struct EnumValueRedirection +{ + EnumValueRedirection(const QString &rej, const QString &us) + : rejected(rej), + used(us) + { + } + QString rejected; + QString used; +}; + +class EnumTypeEntry : public TypeEntry +{ +public: + EnumTypeEntry(const QString &nspace, const QString &enumName, 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 + { + 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; + + QString qualifier() const + { + return m_qualifier; + } + void setQualifier(const QString &q) + { + m_qualifier = q; + } + + virtual bool preferredConversion() const + { + return false; + } + + bool isBoundsChecked() const + { + return m_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; + QList<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; + QString targetLangName() const + { + return m_targetLangName; + } + QString targetLangApiName() const; + virtual bool preferredConversion() const + { + 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 + { + 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; + } + + virtual QString lookupName() const + { + return m_lookupName.isEmpty() ? targetLangName() : m_lookupName; + } + + QString targetLangApiName() const; + + 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; + } + + virtual QString qualifiedCppName() const + { + 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 + { + 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 + { + return true; + } + + virtual bool isNativeIdBased() const + { + 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; + QString targetLangName() const; + QString targetLangPackage() const; + + virtual bool isNativeIdBased() const + { + return false; + } +}; + +class CharTypeEntry : public ValueTypeEntry +{ +public: + CharTypeEntry(const QString &name, double vr) : ValueTypeEntry(name, CharType, vr) + { + setCodeGeneration(GenerateNothing); + } + + QString targetLangApiName() const; + QString targetLangName() const; + QString targetLangPackage() const + { + return QString(); + } + + virtual bool isNativeIdBased() const + { + return false; + } +}; + +class VariantTypeEntry: public ValueTypeEntry +{ +public: + VariantTypeEntry(const QString &name, double vr) : ValueTypeEntry(name, VariantType, vr) { } + + QString targetLangApiName() const; + QString targetLangName() const; + QString targetLangPackage() const; + + virtual bool isNativeIdBased() const + { + 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; + } + + virtual bool isNativeIdBased() const + { + return true; + } + virtual QString qualifiedCppName() const + { + 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; + } + + virtual bool isNativeIdBased() const + { + return true; + } + +private: + InterfaceTypeEntry *m_interface; +}; + +struct TypeRejection +{ + QString class_name; + QString function_name; + QString field_name; + QString enum_name; +}; + +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 QList<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..04b669655 --- /dev/null +++ b/sources/shiboken2/ApiExtractor/typesystem_typedefs.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 TYPESYSTEM_TYPEDEFS_H +#define TYPESYSTEM_TYPEDEFS_H + +#include <QtCore/QHash> +#include <QtCore/QList> + +class CodeSnip; +class ContainerTypeEntry; +class DocModification; +class PrimitiveTypeEntry; +class TemplateEntry; +class TypeEntry; + +struct AddedFunction; +struct FieldModification; +struct FunctionModification; + +typedef QHash<QString, QList<TypeEntry *> > TypeEntryHash; +typedef QHash<QString, TypeEntry *> SingleTypeEntryHash; +typedef QHash<QString, TemplateEntry *> TemplateEntryHash; + +typedef QList<AddedFunction> AddedFunctionList; +typedef QList<CodeSnip> CodeSnipList; +typedef QList<const ContainerTypeEntry *> ContainerTypeEntryList; +typedef QList<DocModification> DocModificationList; +typedef QList<FieldModification> FieldModificationList; +typedef QList<FunctionModification> FunctionModificationList; +typedef QList<const PrimitiveTypeEntry *> PrimitiveTypeEntryList; + +#endif // TYPESYSTEM_TYPEDEFS_H |