summaryrefslogtreecommitdiffstats
path: root/tools/qscxmlc
diff options
context:
space:
mode:
Diffstat (limited to 'tools/qscxmlc')
-rw-r--r--tools/qscxmlc/CMakeLists.txt64
-rw-r--r--tools/qscxmlc/data.t12
-rw-r--r--tools/qscxmlc/doc/qscxmlc.qdoc90
-rw-r--r--tools/qscxmlc/generator.cpp1345
-rw-r--r--tools/qscxmlc/generator.h65
-rw-r--r--tools/qscxmlc/main.cpp29
-rw-r--r--tools/qscxmlc/moc.cpp2215
-rw-r--r--tools/qscxmlc/moc.h306
-rw-r--r--tools/qscxmlc/moc_patches/generator.cpp.patch286
-rw-r--r--tools/qscxmlc/moc_patches/generator.h.patch51
-rw-r--r--tools/qscxmlc/moc_patches/moc.cpp.patch29
-rw-r--r--tools/qscxmlc/moc_patches/moc.h.patch94
-rw-r--r--tools/qscxmlc/moc_patches/outputrevision.h.patch16
-rwxr-xr-xtools/qscxmlc/moc_patches/update_moc.sh94
-rw-r--r--tools/qscxmlc/outputrevision.h37
-rw-r--r--tools/qscxmlc/qscxmlc.cpp47
-rw-r--r--tools/qscxmlc/qscxmlc.h41
-rw-r--r--tools/qscxmlc/qscxmlc.pri32
-rw-r--r--tools/qscxmlc/qscxmlc.pro16
-rw-r--r--tools/qscxmlc/scxmlcppdumper.cpp94
-rw-r--r--tools/qscxmlc/scxmlcppdumper.h32
-rw-r--r--tools/qscxmlc/templates.qrc7
-rw-r--r--tools/qscxmlc/utils.h40
23 files changed, 3937 insertions, 1105 deletions
diff --git a/tools/qscxmlc/CMakeLists.txt b/tools/qscxmlc/CMakeLists.txt
new file mode 100644
index 0000000..98b7b3e
--- /dev/null
+++ b/tools/qscxmlc/CMakeLists.txt
@@ -0,0 +1,64 @@
+# Copyright (C) 2022 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+#####################################################################
+## qscxmlc Tool:
+#####################################################################
+
+qt_internal_include_in_repo_target_set(qtscxml)
+
+qt_get_tool_target_name(target_name qscxmlc)
+qt_internal_add_tool(${target_name}
+ TOOLS_TARGET Scxml
+ INSTALL_DIR "${INSTALL_LIBEXECDIR}"
+ SOURCES
+ ../../src/scxml/qscxmlcompiler.cpp ../../src/scxml/qscxmlcompiler.h ../../src/scxml/qscxmlcompiler_p.h
+ ../../src/scxml/qscxmlerror.cpp ../../src/scxml/qscxmlerror.h
+ ../../src/scxml/qscxmlexecutablecontent.cpp ../../src/scxml/qscxmlexecutablecontent.h ../../src/scxml/qscxmlexecutablecontent_p.h
+ ../../src/scxml/qscxmlglobals.h
+ ../../src/scxml/qscxmltabledata.cpp ../../src/scxml/qscxmltabledata.h
+ generator.cpp generator.h
+ main.cpp
+ moc.cpp moc.h
+ outputrevision.h
+ qscxmlc.cpp qscxmlc.h
+ scxmlcppdumper.cpp scxmlcppdumper.h
+ utils.h
+ DEFINES
+ BUILD_QSCXMLC
+ QT_NO_CAST_FROM_ASCII
+ QT_NO_CAST_TO_ASCII
+ INCLUDE_DIRECTORIES
+ $<TARGET_PROPERTY:Qt::Scxml,INTERFACE_INCLUDE_DIRECTORIES>
+ $<TARGET_PROPERTY:Qt::ScxmlPrivate,INTERFACE_INCLUDE_DIRECTORIES>
+ LIBRARIES
+ Qt::CorePrivate
+)
+qt_internal_return_unless_building_tools()
+
+# qscxmlc uses header and source files from Scxml library instead of linking it. These sources use
+# includes from the module(using the module include style) so need to sync the module header
+# files first to avoid compiler errors.
+add_dependencies(${target_name} Scxml_sync_headers)
+
+set_property(SOURCE ../../src/scxml/qscxmlerror.h PROPERTY SKIP_AUTOMOC ON)
+set_property(SOURCE ../../src/scxml/qscxmlcompiler.cpp PROPERTY SKIP_AUTOMOC ON)
+
+# Resources:
+set(templates_resource_files
+ "cppdatamodel.t"
+ "data.t"
+ "decl.t"
+)
+
+qt_internal_add_resource(${target_name} "templates"
+ PREFIX
+ "/"
+ FILES
+ ${templates_resource_files}
+ OPTIONS --no-compress
+)
+
+
+#### Keys ignored in scope 1:.:.:qscxmlc.pro:<TRUE>:
+# _OPTION = "host_build"
diff --git a/tools/qscxmlc/data.t b/tools/qscxmlc/data.t
index 3926507..1b1e6f7 100644
--- a/tools/qscxmlc/data.t
+++ b/tools/qscxmlc/data.t
@@ -33,7 +33,9 @@ struct ${classname}::Data: private QScxmlTableData {
{
Q_ASSERT(id >= QScxmlExecutableContent::NoString); Q_ASSERT(id < ${stringCount});
if (id == QScxmlExecutableContent::NoString) return QString();
- return QString({static_cast<QStringData*>(strings.data + id)});
+ const auto dataOffset = strings.offsetsAndSize[id * 2];
+ const auto dataSize = strings.offsetsAndSize[id * 2 + 1];
+ return QString::fromRawData(reinterpret_cast<const QChar*>(&strings.stringdata[dataOffset]), dataSize);
}
const qint32 *stateMachineTable() const override final
@@ -82,8 +84,8 @@ struct ${classname}::Data: private QScxmlTableData {
static QScxmlExecutableContent::ForeachInfo foreaches[];
static const qint32 theStateMachineTable[];
static struct Strings {
- QArrayData data[${stringCount}];
- qunicodechar stringdata[${stringdataSize}];
+ const uint offsetsAndSize[${stringCount} * 2];
+ char16_t stringdata[${stringdataSize}];
} strings;
};
@@ -120,10 +122,6 @@ QScxmlExecutableContent::ForeachInfo ${classname}::Data::foreaches[] = {
${foreaches}
};
-#define STR_LIT(idx, ofs, len) \
- Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
- qptrdiff(offsetof(Strings, stringdata) + ofs * sizeof(qunicodechar) - idx * sizeof(QArrayData)) \
- )
${classname}::Data::Strings ${classname}::Data::strings = {{
${strLits}
},{
diff --git a/tools/qscxmlc/doc/qscxmlc.qdoc b/tools/qscxmlc/doc/qscxmlc.qdoc
index bf38a63..7e46b8a 100644
--- a/tools/qscxmlc/doc/qscxmlc.qdoc
+++ b/tools/qscxmlc/doc/qscxmlc.qdoc
@@ -1,29 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the documentation of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:FDL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qscxmlc.html
@@ -39,27 +15,41 @@
\section1 Usage
- The \c qscxml tool is invoked automatically if the QT variable in the
- project file includes \c scxml, and the .scxml file to use is specified
- using the \c STATECHARTS variable.
+ The \c qscxmlc tool is invoked automatically if the project is linked against
+ the \c scxml library in the project file, and the \c .scxml file to use is specified
+ using the special build directives \c STATECHARTS or qt6_add_statecharts.
- \badcode
- QT += scxml
- STATECHARTS = MyStatemachine.scxml
- \endcode
+ When using cmake:
+
+ \include qtscxml-module-use.qdocinc cmakebuild
+ \include qtscxml-module-use.qdocinc cmakestatecharts
+
+ When using qmake:
+
+ \include qtscxml-module-use.qdocinc qmakebuild
+ \include qtscxml-module-use.qdocinc qmakestatecharts
- With above definitions, \c qmake invokes \c qscxmlc to generate
- MyStatemachine.h and MyStatemachine.cpp, and adds them to \l [QMake]
- HEADERS and \l [QMAKE] SOURCES variables.
+ With above definitions, \c qmake or \c cmake invokes \c qscxmlc to generate
+ MyStatemachine.h and MyStatemachine.cpp, and adds them appropriately
+ to the project as headers and sources.
By default, the name of the generated class that implements the state
machine corresponds with the \e name attribute of the \c <scxml> root
element.
+ The \c qscxmlc tool can also be invoked manually and the resulting header and
+ source files can be used as regular source files in a project. When
+ using these source files as part of a \c cmake project, one must
+ additionally disable automatic moc in the CMakeLists.txt file as
+ illustrated by this example:
+ \code
+ set_source_files_properties(statemachine.h PROPERTIES SKIP_AUTOMOC TRUE)
+ \endcode
+ If you omit this, you will see duplicate symbol errors during compilation.
+
\section1 Command-Line Options
- The \c qscxmlc tool supports the following command-line options, which can be specified using
- the \c QSCXMLC_ARGUMENTS variable in the project file:
+ The \c qscxmlc tool supports the following command-line options:
\table
\header
@@ -67,8 +57,7 @@
\li Description
\row
\li \c {--namespace <namespace>}
- \li Put the generated class(es) in the specified namespace. You can use the
- \c QSCXMLC_NAMESPACE variable to specify this in your project file.
+ \li Put the generated class(es) in the specified namespace.
\row
\li \c {-o <base/out/name>}
\li The base name of the output files. This can include a path. If none is specified, the
@@ -90,4 +79,25 @@
state changes with plain QObject::connect() and directly call a method to find out if
a state is currently active.
\endtable
+
+ The \c qmake and \c CMake project files support the following options:
+
+ \table
+ \header
+ \li Option
+ \li Description
+ \row
+ \li \c {QSCXMLC_DIR|OUTPUT_DIRECTORY <directory>}
+ \li \c QSCXMLC_DIR (qmake) or \c OUTPUT_DIRECTORY (cmake) specifies the directory for
+ the output files. OUTPUT_DIR (cmake) has been deprecated.
+ \row
+ \li \c {QSCXMLC_NAMESPACE|NAMESPACE <namespace>}
+ \li \c QSCXMLC_NAMESPACE (qmake) or \c NAMESPACE (cmake) specifies the namespace for the
+ generated classes.
+ \row
+ \li \c {QSCXMLC_ARGUMENTS|OPTIONS <options>}
+ \li \c QSCXMLC_ARGUMENTS (qmake) or \c OPTIONS (cmake) allows specifying additional
+ options for the \c qscxmlc compiler. QSCXMLC_ARGUMENTS with cmake has been
+ deprecated.
+ \endtable
*/
diff --git a/tools/qscxmlc/generator.cpp b/tools/qscxmlc/generator.cpp
index 6febf09..4586c1d 100644
--- a/tools/qscxmlc/generator.cpp
+++ b/tools/qscxmlc/generator.cpp
@@ -1,32 +1,12 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com>
+// Copyright (C) 2018 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "generator.h"
+#if 0 // -- QtScxml
+#include "cbordevice.h"
+#endif // -- QtScxml
#include "outputrevision.h"
#include "utils.h"
#include <QtCore/qmetatype.h>
@@ -35,12 +15,19 @@
#include <QtCore/qjsonvalue.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qplugin.h>
+#include <QtCore/qstringview.h>
-#include <private/qmetaobject_p.h> //for the flags.
+#include <math.h>
#include <stdio.h>
+#include <private/qmetaobject_p.h> //for the flags.
+#include <private/qplugin_p.h> //for the flags.
+
QT_BEGIN_NAMESPACE
+using namespace QtMiscUtils;
+
+// -- QtScxml
void fprintf(QIODevice &out, const char *fmt, ...)
{
va_list argp;
@@ -61,13 +48,14 @@ void fputs(const char *s, QIODevice &out)
{
out.write(s);
}
+// -- QtScxml
uint nameToBuiltinType(const QByteArray &name)
{
if (name.isEmpty())
return 0;
- uint tp = QMetaType::type(name.constData());
+ uint tp = qMetaTypeTypeInternal(name.constData());
return tp < uint(QMetaType::User) ? tp : uint(QMetaType::UnknownType);
}
@@ -76,7 +64,7 @@ uint nameToBuiltinType(const QByteArray &name)
*/
bool isBuiltinType(const QByteArray &type)
{
- int id = QMetaType::type(type.constData());
+ int id = qMetaTypeTypeInternal(type.constData());
if (id == QMetaType::UnknownType)
return false;
return (id < QMetaType::User);
@@ -91,42 +79,73 @@ static const char *metaTypeEnumValueString(int type)
QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING)
}
#undef RETURN_METATYPENAME_STRING
- return 0;
+ return nullptr;
}
-Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, const QHash<QByteArray,
- QByteArray> &knownQObjectClasses, const QHash<QByteArray,
- QByteArray> &knownGadgets, QIODevice &outfile)
- : out(outfile), cdef(classDef), metaTypes(metaTypes), knownQObjectClasses(knownQObjectClasses)
- , knownGadgets(knownGadgets)
+// -- QtScxml
+Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ const QHash<QByteArray, QByteArray> &knownQObjectClasses,
+ const QHash<QByteArray, QByteArray> &knownGadgets,
+ QIODevice &outfile,
+ bool requireCompleteTypes)
+ : out(outfile),
+ cdef(classDef),
+ metaTypes(metaTypes),
+ knownQObjectClasses(knownQObjectClasses),
+ knownGadgets(knownGadgets),
+ requireCompleteTypes(requireCompleteTypes)
{
if (cdef->superclassList.size())
- purestSuperClass = cdef->superclassList.first().first;
+ purestSuperClass = cdef->superclassList.constFirst().classname;
}
+// -- QtScxml
-static inline int lengthOfEscapeSequence(const QByteArray &s, int i)
+#if 0 // -- QtScxml
+static inline qsizetype lengthOfEscapeSequence(const QByteArray &s, qsizetype i)
{
- if (s.at(i) != '\\' || i >= s.length() - 1)
+ if (s.at(i) != '\\' || i >= s.size() - 1)
return 1;
- const int startPos = i;
+ const qsizetype startPos = i;
++i;
char ch = s.at(i);
if (ch == 'x') {
++i;
- while (i < s.length() && is_hex_char(s.at(i)))
+ while (i < s.size() && isHexDigit(s.at(i)))
++i;
- } else if (is_octal_char(ch)) {
+ } else if (isOctalDigit(ch)) {
while (i < startPos + 4
- && i < s.length()
- && is_octal_char(s.at(i))) {
+ && i < s.size()
+ && isOctalDigit(s.at(i))) {
++i;
}
} else { // single character escape sequence
- i = qMin(i + 1, s.length());
+ i = qMin(i + 1, s.size());
}
return i - startPos;
}
+// Prints \a s to \a out, breaking it into lines of at most ColumnWidth. The
+// opening and closing quotes are NOT included (it's up to the caller).
+static void printStringWithIndentation(QIODevice &out, const QByteArray &s) // -- QtScxml
+{
+ static constexpr int ColumnWidth = 72;
+ const qsizetype len = s.size();
+ qsizetype idx = 0;
+
+ do {
+ qsizetype spanLen = qMin(ColumnWidth - 2, len - idx);
+ // don't cut escape sequences at the end of a line
+ const qsizetype backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1);
+ if (backSlashPos >= idx) {
+ const qsizetype escapeLen = lengthOfEscapeSequence(s, backSlashPos);
+ spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, len - idx);
+ }
+ fprintf(out, "\n \"%.*s\"", int(spanLen), s.constData() + idx);
+ idx += spanLen;
+ } while (idx < len);
+}
+#endif // -- QtSxcml
+
void Generator::strreg(const QByteArray &s)
{
if (!strings.contains(s))
@@ -135,7 +154,7 @@ void Generator::strreg(const QByteArray &s)
int Generator::stridx(const QByteArray &s)
{
- int i = strings.indexOf(s);
+ int i = int(strings.indexOf(s));
Q_ASSERT_X(i != -1, Q_FUNC_INFO, "We forgot to register some strings");
return i;
}
@@ -146,8 +165,8 @@ int Generator::stridx(const QByteArray &s)
static int aggregateParameterCount(const QList<FunctionDef> &list)
{
int sum = 0;
- for (int i = 0; i < list.count(); ++i)
- sum += list.at(i).arguments.count() + 1; // +1 for return type
+ for (const FunctionDef &def : list)
+ sum += int(def.arguments.size()) + 1; // +1 for return type
return sum;
}
@@ -166,31 +185,35 @@ bool Generator::registerableMetaType(const QByteArray &propertyType)
return true;
}
- static const QVector<QByteArray> smartPointers = QVector<QByteArray>()
+ static const QList<QByteArray> smartPointers = QList<QByteArray>()
#define STREAM_SMART_POINTER(SMART_POINTER) << #SMART_POINTER
- QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(STREAM_SMART_POINTER)
+ QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(STREAM_SMART_POINTER)
#undef STREAM_SMART_POINTER
- ;
+ ;
- for (const QByteArray &smartPointer : smartPointers)
- if (propertyType.startsWith(smartPointer + "<") && !propertyType.endsWith("&"))
+ for (const QByteArray &smartPointer : smartPointers) {
+ QByteArray ba = smartPointer + "<";
+ if (propertyType.startsWith(ba) && !propertyType.endsWith("&"))
return knownQObjectClasses.contains(propertyType.mid(smartPointer.size() + 1, propertyType.size() - smartPointer.size() - 1 - 1));
+ }
- static const QVector<QByteArray> oneArgTemplates = QVector<QByteArray>()
+ static const QList<QByteArray> oneArgTemplates = QList<QByteArray>()
#define STREAM_1ARG_TEMPLATE(TEMPLATENAME) << #TEMPLATENAME
- QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(STREAM_1ARG_TEMPLATE)
+ QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(STREAM_1ARG_TEMPLATE)
#undef STREAM_1ARG_TEMPLATE
- ;
- for (const QByteArray &oneArgTemplateType : oneArgTemplates)
- if (propertyType.startsWith(oneArgTemplateType + "<") && propertyType.endsWith(">")) {
- const int argumentSize = propertyType.size() - oneArgTemplateType.size() - 1
+ ;
+ for (const QByteArray &oneArgTemplateType : oneArgTemplates) {
+ const QByteArray ba = oneArgTemplateType + "<";
+ if (propertyType.startsWith(ba) && propertyType.endsWith(">")) {
+ const qsizetype argumentSize = propertyType.size() - ba.size()
// The closing '>'
- 1
// templates inside templates have an extra whitespace char to strip.
- (propertyType.at(propertyType.size() - 2) == ' ' ? 1 : 0 );
- const QByteArray templateArg = propertyType.mid(oneArgTemplateType.size() + 1, argumentSize);
+ const QByteArray templateArg = propertyType.sliced(ba.size(), argumentSize);
return isBuiltinType(templateArg) || registerableMetaType(templateArg);
}
+ }
return false;
}
@@ -200,26 +223,41 @@ static bool qualifiedNameEquals(const QByteArray &qualifiedName, const QByteArra
{
if (qualifiedName == name)
return true;
- int index = qualifiedName.indexOf("::");
+ const qsizetype index = qualifiedName.indexOf("::");
if (index == -1)
return false;
return qualifiedNameEquals(qualifiedName.mid(index+2), name);
}
+static QByteArray generateQualifiedClassNameIdentifier(const QByteArray &identifier)
+{
+ QByteArray qualifiedClassNameIdentifier = identifier;
+
+ // Remove ':'s in the name, but be sure not to create any illegal
+ // identifiers in the process. (Don't replace with '_', because
+ // that will create problems with things like NS_::_class.)
+ qualifiedClassNameIdentifier.replace("::", "SCOPE");
+
+ // Also, avoid any leading/trailing underscores (we'll concatenate
+ // the generated name with other prefixes/suffixes, and these latter
+ // may already include an underscore, leading to two underscores)
+ qualifiedClassNameIdentifier = "CLASS" + qualifiedClassNameIdentifier + "ENDCLASS";
+ return qualifiedClassNameIdentifier;
+}
+
void Generator::generateCode()
{
- bool isQt = (cdef->classname == "Qt");
bool isQObject = (cdef->classname == "QObject");
bool isConstructible = !cdef->constructorList.isEmpty();
// filter out undeclared enumerators and sets
{
QList<EnumDef> enumList;
- for (int i = 0; i < cdef->enumList.count(); ++i) {
- EnumDef def = cdef->enumList.at(i);
+ for (EnumDef def : std::as_const(cdef->enumList)) {
if (cdef->enumDeclarations.contains(def.name)) {
enumList += def;
}
+ def.enumName = def.name;
QByteArray alias = cdef->flagAliases.value(def.name);
if (cdef->enumDeclarations.contains(alias)) {
def.name = alias;
@@ -238,102 +276,74 @@ void Generator::generateCode()
registerFunctionStrings(cdef->slotList);
registerFunctionStrings(cdef->methodList);
registerFunctionStrings(cdef->constructorList);
+ registerByteArrayVector(cdef->nonClassSignalList);
registerPropertyStrings();
registerEnumStrings();
- QByteArray qualifiedClassNameIdentifier = cdef->qualified;
- qualifiedClassNameIdentifier.replace(':', '_');
+ const bool hasStaticMetaCall =
+ (cdef->hasQObject || !cdef->methodList.isEmpty()
+ || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty());
+
+ const QByteArray qualifiedClassNameIdentifier = generateQualifiedClassNameIdentifier(cdef->qualified);
+
+ // ensure the qt_meta_stringdata_XXXX_t type is local
+ fprintf(out, "namespace {\n");
//
-// Build stringdata struct
+// Build the strings using QtMocHelpers::StringData
//
- const int constCharArraySizeLimit = 65535;
- fprintf(out, "struct qt_meta_stringdata_%s_t {\n", qualifiedClassNameIdentifier.constData());
- fprintf(out, " QByteArrayData data[%d];\n", strings.size());
- {
- int stringDataLength = 0;
- int stringDataCounter = 0;
- for (int i = 0; i < strings.size(); ++i) {
- int thisLength = strings.at(i).length() + 1;
- stringDataLength += thisLength;
- if (stringDataLength / constCharArraySizeLimit) {
- // save previous stringdata and start computing the next one.
- fprintf(out, " unsigned char stringdata%d[%d];\n", stringDataCounter++,
- stringDataLength - thisLength);
- stringDataLength = thisLength;
- }
- }
- fprintf(out, " unsigned char stringdata%d[%d];\n", stringDataCounter, stringDataLength);
- }
- fprintf(out, "};\n");
-
- // Macro that expands into a QByteArrayData. The offset member is
- // calculated from 1) the offset of the actual characters in the
- // stringdata.stringdata member, and 2) the stringdata.data index of the
- // QByteArrayData being defined. This calculation relies on the
- // QByteArrayData::data() implementation returning simply "this + offset".
- fprintf(out, "#define QT_MOC_LITERAL(idx, ofs, len) \\\n"
- " Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \\\n"
- " qptrdiff(offsetof(qt_meta_stringdata_%s_t, stringdata0) + ofs \\\n"
- " - idx * sizeof(QByteArrayData)) \\\n"
- " )\n",
- qualifiedClassNameIdentifier.constData());
-
- fprintf(out, "static const qt_meta_stringdata_%s_t qt_meta_stringdata_%s = {\n",
+ fprintf(out, "\n#ifdef QT_MOC_HAS_STRINGDATA\n"
+ "struct qt_meta_stringdata_%s_t {};\n"
+ "constexpr auto qt_meta_stringdata_%s = QtMocHelpers::stringData(",
qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
- fprintf(out, " {\n");
{
- int idx = 0;
- for (int i = 0; i < strings.size(); ++i) {
- const QByteArray &str = strings.at(i);
- fprintf(out, "QT_MOC_LITERAL(%d, %d, %d)", i, idx, str.length());
- if (i != strings.size() - 1)
- fputc(',', out);
- const QByteArray comment = str.length() > 32 ? str.left(29) + "..." : str;
- fprintf(out, " // \"%s\"\n", comment.constData());
- idx += str.length() + 1;
- for (int j = 0; j < str.length(); ++j) {
- if (str.at(j) == '\\') {
- int cnt = lengthOfEscapeSequence(str, j) - 1;
- idx -= cnt;
- j += cnt;
- }
- }
+ char comma = 0;
+// -- QtScxml
+ for (qsizetype i = 0, end = strings.size(); i < end; ++i) {
+ if (comma)
+ fputc(comma, out);
+ fprintf(out, "\n {");
+ const QByteArray s = strings.at(i);
+ const qsizetype len = s.size();
+ for (qsizetype charPos = 0; charPos < len; ++charPos)
+ fprintf(out, "char(0x%.2x),", static_cast<quint8>(s.at(charPos)));
+ const bool isLast = (i == end - 1);
+ fprintf(out, "char(0)%s // %d: %s", isLast ? "}" : "},", i, s.constData());
+ comma = ',';
}
- fprintf(out, " },{\n");
- }
+// -- QtScxml
-//
-// Build stringdata array
-//
- for (int i = 0; i < strings.size(); ++i) {
- QByteArray s = strings.at(i);
- int len = s.length();
- for (int charPos = 0; charPos < len; ++charPos)
- fprintf(out, "0x%.2x,", static_cast<quint8>(s.at(charPos)));
- fprintf(out, "0%s // %d: %s\n", i < strings.size() - 1 ? "," : "", i, s.constData());
}
-
-// Terminate stringdata struct
- fprintf(out, " }};\n");
- fprintf(out, "#undef QT_MOC_LITERAL\n\n");
+ fprintf(out, "\n);\n"
+ "#else // !QT_MOC_HAS_STRINGDATA\n");
+ fprintf(out, "#error \"qtmochelpers.h not found or too old.\"\n");
+ fprintf(out, "#endif // !QT_MOC_HAS_STRINGDATA\n");
+ fprintf(out, "} // unnamed namespace\n\n");
//
// build the data array
//
int index = MetaObjectPrivateFieldCount;
- fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
+ fprintf(out, "Q_CONSTINIT static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, "\n // content:\n");
fprintf(out, " %4d, // revision\n", int(QMetaObjectPrivate::OutputRevision));
fprintf(out, " %4d, // classname\n", stridx(cdef->qualified));
- fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
- index += cdef->classInfoList.count() * 2;
+ fprintf(out, " %4d, %4d, // classinfo\n", int(cdef->classInfoList.size()), int(cdef->classInfoList.size() ? index : 0));
+ index += cdef->classInfoList.size() * 2;
+
+ qsizetype methodCount = 0;
+ if (qAddOverflow(cdef->signalList.size(), cdef->slotList.size(), &methodCount)
+ || qAddOverflow(cdef->methodList.size(), methodCount, &methodCount)) {
+// -- QtScxml
+ qFatal("internal limit exceeded: the total number of member functions"
+ " (including signals and slots) is too big.");
+// -- QtScxml
+ }
- int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count();
- fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0);
- index += methodCount * 5;
+ fprintf(out, " %4" PRIdQSIZETYPE ", %4d, // methods\n", methodCount, methodCount ? index : 0);
+ index += methodCount * QMetaObjectPrivate::IntsPerMethod;
if (cdef->revisionedMethods)
index += methodCount;
int paramsIndex = index;
@@ -343,30 +353,27 @@ void Generator::generateCode()
+ aggregateParameterCount(cdef->constructorList);
index += totalParameterCount * 2 // types and parameter names
- methodCount // return "parameters" don't have names
- - cdef->constructorList.count(); // "this" parameters don't have names
+ - int(cdef->constructorList.size()); // "this" parameters don't have names
- fprintf(out, " %4d, %4d, // properties\n", cdef->propertyList.count(), cdef->propertyList.count() ? index : 0);
- index += cdef->propertyList.count() * 3;
- if(cdef->notifyableProperties)
- index += cdef->propertyList.count();
- if (cdef->revisionedProperties)
- index += cdef->propertyList.count();
- fprintf(out, " %4d, %4d, // enums/sets\n", cdef->enumList.count(), cdef->enumList.count() ? index : 0);
+ fprintf(out, " %4d, %4d, // properties\n", int(cdef->propertyList.size()), int(cdef->propertyList.size() ? index : 0));
+ index += cdef->propertyList.size() * QMetaObjectPrivate::IntsPerProperty;
+ fprintf(out, " %4d, %4d, // enums/sets\n", int(cdef->enumList.size()), cdef->enumList.size() ? index : 0);
int enumsIndex = index;
- for (int i = 0; i < cdef->enumList.count(); ++i)
- index += 4 + (cdef->enumList.at(i).values.count() * 2);
- fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? cdef->constructorList.count() : 0,
+ for (const EnumDef &def : std::as_const(cdef->enumList))
+ index += QMetaObjectPrivate::IntsPerEnum + (def.values.size() * 2);
+
+ fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? int(cdef->constructorList.size()) : 0,
isConstructible ? index : 0);
int flags = 0;
- if (cdef->hasQGadget) {
+ if (cdef->hasQGadget || cdef->hasQNamespace) {
// Ideally, all the classes could have that flag. But this broke classes generated
// by qdbusxml2cpp which generate code that require that we call qt_metacall for properties
flags |= PropertyAccessInStaticMetaCall;
}
fprintf(out, " %4d, // flags\n", flags);
- fprintf(out, " %4d, // signalCount\n", cdef->signalList.count());
+ fprintf(out, " %4d, // signalCount\n", int(cdef->signalList.size()));
//
@@ -374,20 +381,31 @@ void Generator::generateCode()
//
generateClassInfos();
+ qsizetype propEnumCount = 0;
+ // all property metatypes + all enum metatypes + 1 for the type of the current class itself
+ if (qAddOverflow(cdef->propertyList.size(), cdef->enumList.size(), &propEnumCount)
+ || qAddOverflow(propEnumCount, qsizetype(1), &propEnumCount)
+ || propEnumCount >= std::numeric_limits<int>::max()) {
+// -- QtScxml
+ qFatal("internal limit exceeded: number of property and enum metatypes is too big.");
+// -- QtScxml
+ }
+ int initialMetaTypeOffset = int(propEnumCount);
+
//
// Build signals array first, otherwise the signal indices would be wrong
//
- generateFunctions(cdef->signalList, "signal", MethodSignal, paramsIndex);
+ generateFunctions(cdef->signalList, "signal", MethodSignal, paramsIndex, initialMetaTypeOffset);
//
// Build slots array
//
- generateFunctions(cdef->slotList, "slot", MethodSlot, paramsIndex);
+ generateFunctions(cdef->slotList, "slot", MethodSlot, paramsIndex, initialMetaTypeOffset);
//
// Build method array
//
- generateFunctions(cdef->methodList, "method", MethodMethod, paramsIndex);
+ generateFunctions(cdef->methodList, "method", MethodMethod, paramsIndex, initialMetaTypeOffset);
//
// Build method version arrays
@@ -421,7 +439,7 @@ void Generator::generateCode()
// Build constructors array
//
if (isConstructible)
- generateFunctions(cdef->constructorList, "constructor", MethodConstructor, paramsIndex);
+ generateFunctions(cdef->constructorList, "constructor", MethodConstructor, paramsIndex, initialMetaTypeOffset);
//
// Terminate data array
@@ -429,41 +447,31 @@ void Generator::generateCode()
fprintf(out, "\n 0 // eod\n};\n\n");
//
-// Generate internal qt_static_metacall() function
-//
- const bool hasStaticMetaCall = !isQt &&
- (cdef->hasQObject || !cdef->methodList.isEmpty()
- || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty());
- if (hasStaticMetaCall)
- generateStaticMetacall();
-
-//
// Build extra array
//
QList<QByteArray> extraList;
- QHash<QByteArray, QByteArray> knownExtraMetaObject = knownGadgets;
+ QMultiHash<QByteArray, QByteArray> knownExtraMetaObject(knownGadgets);
knownExtraMetaObject.unite(knownQObjectClasses);
- for (int i = 0; i < cdef->propertyList.count(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
if (isBuiltinType(p.type))
continue;
if (p.type.contains('*') || p.type.contains('<') || p.type.contains('>'))
continue;
- int s = p.type.lastIndexOf("::");
+ const qsizetype s = p.type.lastIndexOf("::");
if (s <= 0)
continue;
QByteArray unqualifiedScope = p.type.left(s);
// The scope may be a namespace for example, so it's only safe to include scopes that are known QObjects (QTBUG-2151)
- QHash<QByteArray, QByteArray>::ConstIterator scopeIt;
+ QMultiHash<QByteArray, QByteArray>::ConstIterator scopeIt;
QByteArray thisScope = cdef->qualified;
do {
- int s = thisScope.lastIndexOf("::");
+ const qsizetype s = thisScope.lastIndexOf("::");
thisScope = thisScope.left(s);
QByteArray currentScope = thisScope.isEmpty() ? unqualifiedScope : thisScope + "::" + unqualifiedScope;
scopeIt = knownExtraMetaObject.constFind(currentScope);
@@ -486,10 +494,10 @@ void Generator::generateCode()
// QTBUG-20639 - Accept non-local enums for QML signal/slot parameters.
// Look for any scoped enum declarations, and add those to the list
// of extra/related metaobjects for this object.
- QList<QByteArray> enumKeys = cdef->enumDeclarations.keys();
- for (int i = 0; i < enumKeys.count(); ++i) {
- const QByteArray &enumKey = enumKeys[i];
- int s = enumKey.lastIndexOf("::");
+ for (auto it = cdef->enumDeclarations.keyBegin(),
+ end = cdef->enumDeclarations.keyEnd(); it != end; ++it) {
+ const QByteArray &enumKey = *it;
+ const qsizetype s = enumKey.lastIndexOf("::");
if (s > 0) {
QByteArray scope = enumKey.left(s);
if (scope != "Qt" && !qualifiedNameEquals(cdef->qualified, scope) && !extraList.contains(scope))
@@ -497,44 +505,114 @@ void Generator::generateCode()
}
}
+//
+// Generate meta object link to parent meta objects
+//
+
if (!extraList.isEmpty()) {
- fprintf(out, "static const QMetaObject * const qt_meta_extradata_%s[] = {\n ", qualifiedClassNameIdentifier.constData());
- for (int i = 0; i < extraList.count(); ++i) {
- fprintf(out, " &%s::staticMetaObject,\n", extraList.at(i).constData());
- }
+ fprintf(out, "Q_CONSTINIT static const QMetaObject::SuperData qt_meta_extradata_%s[] = {\n",
+ qualifiedClassNameIdentifier.constData());
+ for (const QByteArray &ba : std::as_const(extraList))
+ fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", ba.constData());
+
fprintf(out, " nullptr\n};\n\n");
}
//
// Finally create and initialize the static meta object
//
- if (isQt)
- fprintf(out, "const QMetaObject QObject::staticQtMetaObject = {\n");
- else
- fprintf(out, "const QMetaObject %s::staticMetaObject = {\n", cdef->qualified.constData());
+ fprintf(out, "Q_CONSTINIT const QMetaObject %s::staticMetaObject = { {\n",
+ cdef->qualified.constData());
if (isQObject)
- fprintf(out, " { nullptr, ");
- else if (cdef->superclassList.size() && (!cdef->hasQGadget || knownGadgets.contains(purestSuperClass)))
- fprintf(out, " { &%s::staticMetaObject, ", purestSuperClass.constData());
+ fprintf(out, " nullptr,\n");
+ else if (cdef->superclassList.size() && !cdef->hasQGadget && !cdef->hasQNamespace) // for qobject, we know the super class must have a static metaobject
+ fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", purestSuperClass.constData());
+ else if (cdef->superclassList.size()) // for gadgets we need to query at compile time for it
+ fprintf(out, " QtPrivate::MetaObjectForType<%s>::value,\n", purestSuperClass.constData());
else
- fprintf(out, " { nullptr, ");
- fprintf(out, "qt_meta_stringdata_%s.data,\n"
- " qt_meta_data_%s, ", qualifiedClassNameIdentifier.constData(),
+ fprintf(out, " nullptr,\n");
+ fprintf(out, " qt_meta_stringdata_%s.offsetsAndSizes,\n"
+ " qt_meta_data_%s,\n", qualifiedClassNameIdentifier.constData(),
qualifiedClassNameIdentifier.constData());
if (hasStaticMetaCall)
- fprintf(out, " qt_static_metacall, ");
+ fprintf(out, " qt_static_metacall,\n");
else
- fprintf(out, " nullptr, ");
+ fprintf(out, " nullptr,\n");
if (extraList.isEmpty())
- fprintf(out, "nullptr, ");
+ fprintf(out, " nullptr,\n");
else
- fprintf(out, "qt_meta_extradata_%s, ", qualifiedClassNameIdentifier.constData());
- fprintf(out, "nullptr}\n};\n\n");
+ fprintf(out, " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData());
+
+ const char *comma = "";
+ const bool requireCompleteness = requireCompleteTypes || cdef->requireCompleteMethodTypes;
+ auto stringForType = [requireCompleteness](const QByteArray &type, bool forceComplete) -> QByteArray {
+ const char *forceCompleteType = forceComplete ? ", std::true_type>" : ", std::false_type>";
+ if (requireCompleteness)
+ return type;
+ return "QtPrivate::TypeAndForceComplete<" % type % forceCompleteType;
+ };
+ if (!requireCompleteness) {
+ fprintf(out, " qt_incomplete_metaTypeArray<qt_meta_stringdata_%s_t", qualifiedClassNameIdentifier.constData());
+ comma = ",";
+ } else {
+ fprintf(out, " qt_metaTypeArray<");
+ }
+ // metatypes for properties
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
+ fprintf(out, "%s\n // property '%s'\n %s",
+ comma, p.name.constData(), stringForType(p.type, true).constData());
+ comma = ",";
+ }
- if(isQt)
- return;
+ // metatypes for enums
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
+ fprintf(out, "%s\n // enum '%s'\n %s",
+ comma, e.name.constData(), stringForType(e.qualifiedType(cdef), true).constData());
+ comma = ",";
+ }
+
+ // type name for the Q_OJBECT/GADGET itself, void for namespaces
+ auto ownType = !cdef->hasQNamespace ? cdef->classname.data() : "void";
+ fprintf(out, "%s\n // Q_OBJECT / Q_GADGET\n %s",
+ comma, stringForType(ownType, true).constData());
+ comma = ",";
+
+ // metatypes for all exposed methods
+ // because we definitely printed something above, this section doesn't need comma control
+ const auto allMethods = {&cdef->signalList, &cdef->slotList, &cdef->methodList};
+ for (const QList<FunctionDef> *methodContainer : allMethods) {
+ for (const FunctionDef &fdef : *methodContainer) {
+ fprintf(out, ",\n // method '%s'\n %s",
+ fdef.name.constData(), stringForType(fdef.type.name, false).constData());
+ for (const auto &argument: fdef.arguments)
+ fprintf(out, ",\n %s", stringForType(argument.type.name, false).constData());
+ }
+ }
+
+ // but constructors have no return types, so this needs comma control again
+ for (const FunctionDef &fdef : std::as_const(cdef->constructorList)) {
+ if (fdef.arguments.isEmpty())
+ continue;
+
+ fprintf(out, "%s\n // constructor '%s'", comma, fdef.name.constData());
+ comma = "";
+ for (const auto &argument: fdef.arguments) {
+ fprintf(out, "%s\n %s", comma,
+ stringForType(argument.type.name, false).constData());
+ comma = ",";
+ }
+ }
+ fprintf(out, "\n >,\n");
+
+ fprintf(out, " nullptr\n} };\n\n");
+
+//
+// Generate internal qt_static_metacall() function
+//
+ if (hasStaticMetaCall)
+ generateStaticMetacall();
if (!cdef->hasQObject)
return;
@@ -542,30 +620,35 @@ void Generator::generateCode()
fprintf(out, "\nconst QMetaObject *%s::metaObject() const\n{\n return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;\n}\n",
cdef->qualified.constData());
+
//
// Generate smart cast function
//
fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
fprintf(out, " if (!_clname) return nullptr;\n");
- fprintf(out, " if (!strcmp(_clname, reinterpret_cast<const char *>(\n"
- " qt_meta_stringdata_%s.stringdata0)))\n"
- " return static_cast<void*>(const_cast< %s*>(this));\n",
- qualifiedClassNameIdentifier.constData(), cdef->classname.constData());
- for (int i = 1; i < cdef->superclassList.size(); ++i) { // for all superclasses but the first one
- if (cdef->superclassList.at(i).second == FunctionDef::Private)
- continue;
- const char *cname = cdef->superclassList.at(i).first.constData();
- fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(const_cast< %s*>(this));\n",
- cname, cname, cdef->classname.constData());
+ fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n"
+ " return static_cast<void*>(this);\n",
+ qualifiedClassNameIdentifier.constData());
+
+ // for all superclasses but the first one
+ if (cdef->superclassList.size() > 1) {
+ auto it = cdef->superclassList.cbegin() + 1;
+ const auto end = cdef->superclassList.cend();
+ for (; it != end; ++it) {
+ if (it->access == FunctionDef::Private)
+ continue;
+ const char *cname = it->classname.constData();
+ fprintf(out, " if (!strcmp(_clname, \"%s\"))\n return static_cast< %s*>(this);\n",
+ cname, cname);
+ }
}
- for (int i = 0; i < cdef->interfaceList.size(); ++i) {
- const QList<ClassDef::Interface> &iface = cdef->interfaceList.at(i);
- for (int j = 0; j < iface.size(); ++j) {
+
+ for (const QList<ClassDef::Interface> &iface : std::as_const(cdef->interfaceList)) {
+ for (qsizetype j = 0; j < iface.size(); ++j) {
fprintf(out, " if (!strcmp(_clname, %s))\n return ", iface.at(j).interfaceId.constData());
- for (int k = j; k >= 0; --k)
+ for (qsizetype k = j; k >= 0; --k)
fprintf(out, "static_cast< %s*>(", iface.at(k).className.constData());
- fprintf(out, "const_cast< %s*>(this)%s;\n",
- cdef->classname.constData(), QByteArray(j+1, ')').constData());
+ fprintf(out, "this%s;\n", QByteArray(j + 1, ')').constData());
}
}
if (!purestSuperClass.isEmpty() && !isQObject) {
@@ -584,21 +667,51 @@ void Generator::generateCode()
//
// Generate internal signal functions
//
- for (int signalindex = 0; signalindex < cdef->signalList.size(); ++signalindex)
- generateSignal(&cdef->signalList[signalindex], signalindex);
+ for (int signalindex = 0; signalindex < int(cdef->signalList.size()); ++signalindex)
+ generateSignal(&cdef->signalList.at(signalindex), signalindex);
- fprintf(out, "\n");
//
// Generate plugin meta data
//
-// generatePluginMetaData();
+#if 0 // -- QtScxml
+ generatePluginMetaData();
+#endif // -- QtScxml
+
+//
+// Generate function to make sure the non-class signals exist in the parent classes
+//
+ if (!cdef->nonClassSignalList.isEmpty()) {
+ fprintf(out, "namespace CheckNotifySignalValidity_%s {\n", qualifiedClassNameIdentifier.constData());
+ for (const QByteArray &nonClassSignal : std::as_const(cdef->nonClassSignalList)) {
+ const auto propertyIt = std::find_if(cdef->propertyList.constBegin(),
+ cdef->propertyList.constEnd(),
+ [&nonClassSignal](const PropertyDef &p) {
+ return nonClassSignal == p.notify;
+ });
+ // must find something, otherwise checkProperties wouldn't have inserted an entry into nonClassSignalList
+ Q_ASSERT(propertyIt != cdef->propertyList.constEnd());
+ fprintf(out, "template<typename T> using has_nullary_%s = decltype(std::declval<T>().%s());\n",
+ nonClassSignal.constData(),
+ nonClassSignal.constData());
+ const auto &propertyType = propertyIt->type;
+ fprintf(out, "template<typename T> using has_unary_%s = decltype(std::declval<T>().%s(std::declval<%s>()));\n",
+ nonClassSignal.constData(),
+ nonClassSignal.constData(),
+ propertyType.constData());
+ fprintf(out, "static_assert(qxp::is_detected_v<has_nullary_%s, %s> || qxp::is_detected_v<has_unary_%s, %s>,\n"
+ " \"NOTIFY signal %s does not exist in class (or is private in its parent)\");\n",
+ nonClassSignal.constData(), cdef->qualified.constData(),
+ nonClassSignal.constData(), cdef->qualified.constData(),
+ nonClassSignal.constData());
+ }
+ fprintf(out, "}\n");
+ }
}
void Generator::registerClassInfoStrings()
{
- for (int i = 0; i < cdef->classInfoList.size(); ++i) {
- const ClassInfoDef &c = cdef->classInfoList.at(i);
+ for (const ClassInfoDef &c : std::as_const(cdef->classInfoList)) {
strreg(c.name);
strreg(c.value);
}
@@ -611,25 +724,19 @@ void Generator::generateClassInfos()
fprintf(out, "\n // classinfo: key, value\n");
- for (int i = 0; i < cdef->classInfoList.size(); ++i) {
- const ClassInfoDef &c = cdef->classInfoList.at(i);
+ for (const ClassInfoDef &c : std::as_const(cdef->classInfoList))
fprintf(out, " %4d, %4d,\n", stridx(c.name), stridx(c.value));
- }
}
void Generator::registerFunctionStrings(const QList<FunctionDef> &list)
{
- for (int i = 0; i < list.count(); ++i) {
- const FunctionDef &f = list.at(i);
-
+ for (const FunctionDef &f : list) {
strreg(f.name);
if (!isBuiltinType(f.normalizedType))
strreg(f.normalizedType);
strreg(f.tag);
- int argsCount = f.arguments.count();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
+ for (const ArgumentDef &a : f.arguments) {
if (!isBuiltinType(a.normalizedType))
strreg(a.normalizedType);
strreg(a.name);
@@ -637,17 +744,22 @@ void Generator::registerFunctionStrings(const QList<FunctionDef> &list)
}
}
-void Generator::generateFunctions(const QList<FunctionDef> &list, const char *functype, int type, int &paramsIndex)
+void Generator::registerByteArrayVector(const QList<QByteArray> &list)
+{
+ for (const QByteArray &ba : list)
+ strreg(ba);
+}
+
+void Generator::generateFunctions(const QList<FunctionDef> &list, const char *functype, int type,
+ int &paramsIndex, int &initialMetatypeOffset)
{
if (list.isEmpty())
return;
- fprintf(out, "\n // %ss: name, argc, parameters, tag, flags\n", functype);
-
- for (int i = 0; i < list.count(); ++i) {
- const FunctionDef &f = list.at(i);
+ fprintf(out, "\n // %ss: name, argc, parameters, tag, flags, initial metatype offsets\n", functype);
+ for (const FunctionDef &f : list) {
QByteArray comment;
- unsigned char flags = type;
+ uint flags = type;
if (f.access == FunctionDef::Private) {
flags |= AccessPrivate;
comment.append("Private");
@@ -675,22 +787,27 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu
comment.append(" | MethodRevisioned");
}
- int argc = f.arguments.count();
- fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x /* %s */,\n",
- stridx(f.name), argc, paramsIndex, stridx(f.tag), flags, comment.constData());
+ if (f.isConst) {
+ flags |= MethodIsConst;
+ comment.append(" | MethodIsConst ");
+ }
+
+ const int argc = int(f.arguments.size());
+ fprintf(out, " %4d, %4d, %4d, %4d, 0x%02x, %4d /* %s */,\n",
+ stridx(f.name), argc, paramsIndex, stridx(f.tag), flags, initialMetatypeOffset, comment.constData());
paramsIndex += 1 + argc * 2;
+ // constructors don't have a return type
+ initialMetatypeOffset += (f.isConstructor ? 0 : 1) + argc;
}
}
void Generator::generateFunctionRevisions(const QList<FunctionDef> &list, const char *functype)
{
- if (list.count())
+ if (list.size())
fprintf(out, "\n // %ss: revision\n", functype);
- for (int i = 0; i < list.count(); ++i) {
- const FunctionDef &f = list.at(i);
+ for (const FunctionDef &f : list)
fprintf(out, " %4d,\n", f.revision);
- }
}
void Generator::generateFunctionParameters(const QList<FunctionDef> &list, const char *functype)
@@ -698,25 +815,22 @@ void Generator::generateFunctionParameters(const QList<FunctionDef> &list, const
if (list.isEmpty())
return;
fprintf(out, "\n // %ss: parameters\n", functype);
- for (int i = 0; i < list.count(); ++i) {
- const FunctionDef &f = list.at(i);
+ for (const FunctionDef &f : list) {
fprintf(out, " ");
// Types
- int argsCount = f.arguments.count();
- for (int j = -1; j < argsCount; ++j) {
- if (j > -1)
- fputc(' ', out);
- const QByteArray &typeName = (j < 0) ? f.normalizedType : f.arguments.at(j).normalizedType;
- generateTypeInfo(typeName, /*allowEmptyName=*/f.isConstructor);
+ const bool allowEmptyName = f.isConstructor;
+ generateTypeInfo(f.normalizedType, allowEmptyName);
+ fputc(',', out);
+ for (const ArgumentDef &arg : f.arguments) {
+ fputc(' ', out);
+ generateTypeInfo(arg.normalizedType, allowEmptyName);
fputc(',', out);
}
// Parameter names
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &arg = f.arguments.at(j);
+ for (const ArgumentDef &arg : f.arguments)
fprintf(out, " %4d,", stridx(arg.name));
- }
fprintf(out, "\n");
}
@@ -749,8 +863,7 @@ void Generator::generateTypeInfo(const QByteArray &typeName, bool allowEmptyName
void Generator::registerPropertyStrings()
{
- for (int i = 0; i < cdef->propertyList.count(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
strreg(p.name);
if (!isBuiltinType(p.type))
strreg(p.type);
@@ -763,10 +876,9 @@ void Generator::generateProperties()
// Create meta data
//
- if (cdef->propertyList.count())
+ if (cdef->propertyList.size())
fprintf(out, "\n // properties: name, type, flags\n");
- for (int i = 0; i < cdef->propertyList.count(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
uint flags = Invalid;
if (!isBuiltinType(p.type))
flags |= EnumOrFlag;
@@ -779,81 +891,52 @@ void Generator::generateProperties()
if (p.stdCppSet())
flags |= StdCppSet;
}
+
if (!p.reset.isEmpty())
flags |= Resettable;
-// if (p.override)
-// flags |= Override;
-
- if (p.designable.isEmpty())
- flags |= ResolveDesignable;
- else if (p.designable != "false")
+ if (p.designable != "false")
flags |= Designable;
- if (p.scriptable.isEmpty())
- flags |= ResolveScriptable;
- else if (p.scriptable != "false")
+ if (p.scriptable != "false")
flags |= Scriptable;
- if (p.stored.isEmpty())
- flags |= ResolveStored;
- else if (p.stored != "false")
+ if (p.stored != "false")
flags |= Stored;
- if (p.editable.isEmpty())
- flags |= ResolveEditable;
- else if (p.editable != "false")
- flags |= Editable;
-
- if (p.user.isEmpty())
- flags |= ResolveUser;
- else if (p.user != "false")
+ if (p.user != "false")
flags |= User;
- if (p.notifyId != -1)
- flags |= Notify;
-
- if (p.revision > 0)
- flags |= Revisioned;
-
if (p.constant)
flags |= Constant;
if (p.final)
flags |= Final;
+ if (p.required)
+ flags |= Required;
+
+ if (!p.bind.isEmpty())
+ flags |= Bindable;
fprintf(out, " %4d, ", stridx(p.name));
generateTypeInfo(p.type);
- fprintf(out, ", 0x%.8x,\n", flags);
- }
-
- if(cdef->notifyableProperties) {
- fprintf(out, "\n // properties: notify_signal_id\n");
- for (int i = 0; i < cdef->propertyList.count(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
- if(p.notifyId == -1)
- fprintf(out, " %4d,\n",
- 0);
- else
- fprintf(out, " %4d,\n",
- p.notifyId);
- }
- }
- if (cdef->revisionedProperties) {
- fprintf(out, "\n // properties: revision\n");
- for (int i = 0; i < cdef->propertyList.count(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
- fprintf(out, " %4d,\n", p.revision);
+ int notifyId = p.notifyId;
+ if (p.notifyId < -1) {
+ // signal is in parent class
+ const int indexInStrings = int(strings.indexOf(p.notify));
+ notifyId = indexInStrings | IsUnresolvedSignal;
}
+ fprintf(out, ", 0x%.8x, uint(%d), %d,\n", flags, notifyId, p.revision);
}
}
void Generator::registerEnumStrings()
{
- for (int i = 0; i < cdef->enumList.count(); ++i) {
- const EnumDef &e = cdef->enumList.at(i);
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
strreg(e.name);
- for (int j = 0; j < e.values.count(); ++j)
- strreg(e.values.at(j));
+ if (!e.enumName.isNull())
+ strreg(e.enumName);
+ for (const QByteArray &val : e.values)
+ strreg(val);
}
}
@@ -862,27 +945,31 @@ void Generator::generateEnums(int index)
if (cdef->enumDeclarations.isEmpty())
return;
- fprintf(out, "\n // enums: name, flags, count, data\n");
- index += 4 * cdef->enumList.count();
+ fprintf(out, "\n // enums: name, alias, flags, count, data\n");
+ index += QMetaObjectPrivate::IntsPerEnum * cdef->enumList.size();
int i;
- for (i = 0; i < cdef->enumList.count(); ++i) {
+ for (i = 0; i < cdef->enumList.size(); ++i) {
const EnumDef &e = cdef->enumList.at(i);
- fprintf(out, " %4d, 0x%.1x, %4d, %4d,\n",
+ int flags = 0;
+ if (cdef->enumDeclarations.value(e.name))
+ flags |= EnumIsFlag;
+ if (e.isEnumClass)
+ flags |= EnumIsScoped;
+ fprintf(out, " %4d, %4d, 0x%.1x, %4d, %4d,\n",
stridx(e.name),
- cdef->enumDeclarations.value(e.name) ? 1 : 0,
- e.values.count(),
+ e.enumName.isNull() ? stridx(e.name) : stridx(e.enumName),
+ flags,
+ int(e.values.size()),
index);
- index += e.values.count() * 2;
+ index += e.values.size() * 2;
}
fprintf(out, "\n // enum data: key, value\n");
- for (i = 0; i < cdef->enumList.count(); ++i) {
- const EnumDef &e = cdef->enumList.at(i);
- for (int j = 0; j < e.values.count(); ++j) {
- const QByteArray &val = e.values.at(j);
+ for (const EnumDef &e : std::as_const(cdef->enumList)) {
+ for (const QByteArray &val : e.values) {
QByteArray code = cdef->qualified.constData();
if (e.isEnumClass)
- code += "::" + e.name;
+ code += "::" + (e.enumName.isNull() ? e.name : e.enumName);
code += "::" + val;
fprintf(out, " %4d, uint(%s),\n",
stridx(val), code.constData());
@@ -902,8 +989,6 @@ void Generator::generateMetacall()
fprintf(out, " _id = %s::qt_metacall(_c, _id, _a);\n", superClass.constData());
}
- fprintf(out, " if (_id < 0)\n return _id;\n");
- fprintf(out, " ");
bool needElse = false;
QList<FunctionDef> methodList;
@@ -911,156 +996,54 @@ void Generator::generateMetacall()
methodList += cdef->slotList;
methodList += cdef->methodList;
+ // If there are no methods or properties, we will return _id anyway, so
+ // don't emit this comparison -- it is unnecessary, and it makes coverity
+ // unhappy.
+ if (methodList.size() || cdef->propertyList.size()) {
+ fprintf(out, " if (_id < 0)\n return _id;\n");
+ }
+
+ fprintf(out, " ");
+
if (methodList.size()) {
needElse = true;
fprintf(out, "if (_c == QMetaObject::InvokeMetaMethod) {\n");
- fprintf(out, " if (_id < %d)\n", methodList.size());
+ fprintf(out, " if (_id < %d)\n", int(methodList.size()));
fprintf(out, " qt_static_metacall(this, _c, _id, _a);\n");
- fprintf(out, " _id -= %d;\n }", methodList.size());
+ fprintf(out, " _id -= %d;\n }", int(methodList.size()));
fprintf(out, " else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {\n");
- fprintf(out, " if (_id < %d)\n", methodList.size());
+ fprintf(out, " if (_id < %d)\n", int(methodList.size()));
if (methodsWithAutomaticTypesHelper(methodList).isEmpty())
- fprintf(out, " *reinterpret_cast<int*>(_a[0]) = -1;\n");
+ fprintf(out, " *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType();\n");
else
fprintf(out, " qt_static_metacall(this, _c, _id, _a);\n");
- fprintf(out, " _id -= %d;\n }", methodList.size());
+ fprintf(out, " _id -= %d;\n }", int(methodList.size()));
}
if (cdef->propertyList.size()) {
- bool needDesignable = false;
- bool needScriptable = false;
- bool needStored = false;
- bool needEditable = false;
- bool needUser = false;
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
- needDesignable |= p.designable.endsWith(')');
- needScriptable |= p.scriptable.endsWith(')');
- needStored |= p.stored.endsWith(')');
- needEditable |= p.editable.endsWith(')');
- needUser |= p.user.endsWith(')');
- }
-
- fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
if (needElse)
fprintf(out, "else ");
fprintf(out,
"if (_c == QMetaObject::ReadProperty || _c == QMetaObject::WriteProperty\n"
- " || _c == QMetaObject::ResetProperty || _c == QMetaObject::RegisterPropertyMetaType) {\n"
+ " || _c == QMetaObject::ResetProperty || _c == QMetaObject::BindableProperty\n"
+ " || _c == QMetaObject::RegisterPropertyMetaType) {\n"
" qt_static_metacall(this, _c, _id, _a);\n"
- " _id -= %d;\n }", cdef->propertyList.count());
-
- fprintf(out, " else ");
- fprintf(out, "if (_c == QMetaObject::QueryPropertyDesignable) {\n");
- if (needDesignable) {
- fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
- fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
- const PropertyDef &p = cdef->propertyList.at(propindex);
- if (!p.designable.endsWith(')'))
- continue;
- fprintf(out, " case %d: *_b = %s; break;\n",
- propindex, p.designable.constData());
- }
- fprintf(out, " default: break;\n");
- fprintf(out, " }\n");
- }
- fprintf(out,
- " _id -= %d;\n"
- " }", cdef->propertyList.count());
-
- fprintf(out, " else ");
- fprintf(out, "if (_c == QMetaObject::QueryPropertyScriptable) {\n");
- if (needScriptable) {
- fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
- fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
- const PropertyDef &p = cdef->propertyList.at(propindex);
- if (!p.scriptable.endsWith(')'))
- continue;
- fprintf(out, " case %d: *_b = %s; break;\n",
- propindex, p.scriptable.constData());
- }
- fprintf(out, " default: break;\n");
- fprintf(out, " }\n");
- }
- fprintf(out,
- " _id -= %d;\n"
- " }", cdef->propertyList.count());
-
- fprintf(out, " else ");
- fprintf(out, "if (_c == QMetaObject::QueryPropertyStored) {\n");
- if (needStored) {
- fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
- fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
- const PropertyDef &p = cdef->propertyList.at(propindex);
- if (!p.stored.endsWith(')'))
- continue;
- fprintf(out, " case %d: *_b = %s; break;\n",
- propindex, p.stored.constData());
- }
- fprintf(out, " default: break;\n");
- fprintf(out, " }\n");
- }
- fprintf(out,
- " _id -= %d;\n"
- " }", cdef->propertyList.count());
-
- fprintf(out, " else ");
- fprintf(out, "if (_c == QMetaObject::QueryPropertyEditable) {\n");
- if (needEditable) {
- fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
- fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
- const PropertyDef &p = cdef->propertyList.at(propindex);
- if (!p.editable.endsWith(')'))
- continue;
- fprintf(out, " case %d: *_b = %s; break;\n",
- propindex, p.editable.constData());
- }
- fprintf(out, " default: break;\n");
- fprintf(out, " }\n");
- }
- fprintf(out,
- " _id -= %d;\n"
- " }", cdef->propertyList.count());
-
-
- fprintf(out, " else ");
- fprintf(out, "if (_c == QMetaObject::QueryPropertyUser) {\n");
- if (needUser) {
- fprintf(out, " bool *_b = reinterpret_cast<bool*>(_a[0]);\n");
- fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
- const PropertyDef &p = cdef->propertyList.at(propindex);
- if (!p.user.endsWith(')'))
- continue;
- fprintf(out, " case %d: *_b = %s; break;\n",
- propindex, p.user.constData());
- }
- fprintf(out, " default: break;\n");
- fprintf(out, " }\n");
- }
- fprintf(out,
- " _id -= %d;\n"
- " }", cdef->propertyList.count());
-
- fprintf(out, "\n#endif // QT_NO_PROPERTIES");
+ " _id -= %d;\n }", int(cdef->propertyList.size()));
}
- if (methodList.size() || cdef->signalList.size() || cdef->propertyList.size())
+ if (methodList.size() || cdef->propertyList.size())
fprintf(out, "\n ");
fprintf(out,"return _id;\n}\n");
}
+// ### Qt 7 (6.x?): remove
QMultiMap<QByteArray, int> Generator::automaticPropertyMetaTypesHelper()
{
QMultiMap<QByteArray, int> automaticPropertyMetaTypes;
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
+ for (int i = 0; i < int(cdef->propertyList.size()); ++i) {
const QByteArray propertyType = cdef->propertyList.at(i).type;
if (registerableMetaType(propertyType) && !isBuiltinType(propertyType))
automaticPropertyMetaTypes.insert(propertyType, i);
@@ -1068,12 +1051,13 @@ QMultiMap<QByteArray, int> Generator::automaticPropertyMetaTypesHelper()
return automaticPropertyMetaTypes;
}
-QMap<int, QMultiMap<QByteArray, int> > Generator::methodsWithAutomaticTypesHelper(const QList<FunctionDef> &methodList)
+QMap<int, QMultiMap<QByteArray, int>>
+Generator::methodsWithAutomaticTypesHelper(const QList<FunctionDef> &methodList)
{
QMap<int, QMultiMap<QByteArray, int> > methodsWithAutomaticTypes;
for (int i = 0; i < methodList.size(); ++i) {
const FunctionDef &f = methodList.at(i);
- for (int j = 0; j < f.arguments.count(); ++j) {
+ for (int j = 0; j < f.arguments.size(); ++j) {
const QByteArray argType = f.arguments.at(j).normalizedType;
if (registerableMetaType(argType) && !isBuiltinType(argType))
methodsWithAutomaticTypes[i].insert(argType, j);
@@ -1090,30 +1074,43 @@ void Generator::generateStaticMetacall()
bool needElse = false;
bool isUsed_a = false;
+ const auto generateCtorArguments = [&](int ctorindex) {
+ const FunctionDef &f = cdef->constructorList.at(ctorindex);
+ Q_ASSERT(!f.isPrivateSignal); // That would be a strange ctor indeed
+ int offset = 1;
+
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
+ fprintf(out, ",");
+ fprintf(out, "(*reinterpret_cast<%s>(_a[%d]))",
+ a.typeNameForCast.constData(), offset++);
+ }
+ };
+
if (!cdef->constructorList.isEmpty()) {
fprintf(out, " if (_c == QMetaObject::CreateInstance) {\n");
fprintf(out, " switch (_id) {\n");
- for (int ctorindex = 0; ctorindex < cdef->constructorList.count(); ++ctorindex) {
+ const int ctorend = int(cdef->constructorList.size());
+ for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) {
fprintf(out, " case %d: { %s *_r = new %s(", ctorindex,
cdef->classname.constData(), cdef->classname.constData());
- const FunctionDef &f = cdef->constructorList.at(ctorindex);
- int offset = 1;
-
- int argsCount = f.arguments.count();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
- fprintf(out, ",");
- fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))", a.typeNameForCast.constData(), offset++);
- }
- if (f.isPrivateSignal) {
- if (argsCount > 0)
- fprintf(out, ", ");
- fprintf(out, "%s", QByteArray("QPrivateSignal()").constData());
- }
+ generateCtorArguments(ctorindex);
fprintf(out, ");\n");
fprintf(out, " if (_a[0]) *reinterpret_cast<%s**>(_a[0]) = _r; } break;\n",
- cdef->hasQGadget ? "void" : "QObject");
+ (cdef->hasQGadget || cdef->hasQNamespace) ? "void" : "QObject");
+ }
+ fprintf(out, " default: break;\n");
+ fprintf(out, " }\n");
+ fprintf(out, " } else if (_c == QMetaObject::ConstructInPlace) {\n");
+ fprintf(out, " switch (_id) {\n");
+ for (int ctorindex = 0; ctorindex < ctorend; ++ctorindex) {
+ fprintf(out, " case %d: { new (_a[0]) %s(",
+ ctorindex, cdef->classname.constData());
+ generateCtorArguments(ctorindex);
+ fprintf(out, "); } break;\n");
}
fprintf(out, " default: break;\n");
fprintf(out, " }\n");
@@ -1137,25 +1134,23 @@ void Generator::generateStaticMetacall()
#ifndef QT_NO_DEBUG
fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n");
#endif
- fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
+ fprintf(out, " auto *_t = static_cast<%s *>(_o);\n", cdef->classname.constData());
} else {
- fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
+ fprintf(out, " auto *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData());
}
- fprintf(out, " Q_UNUSED(_t)\n");
+ fprintf(out, " (void)_t;\n");
fprintf(out, " switch (_id) {\n");
for (int methodindex = 0; methodindex < methodList.size(); ++methodindex) {
const FunctionDef &f = methodList.at(methodindex);
Q_ASSERT(!f.normalizedType.isEmpty());
fprintf(out, " case %d: ", methodindex);
-
- //---- Changed from the original in moc
+ // -- QtScxml
if (f.implementation) {
fprintf(out, f.implementation, "_o", methodindex);
fprintf(out, " break;\n");
continue;
}
- //---- End of change
-
+ // -- QtScxml
if (f.normalizedType != "void")
fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
fprintf(out, "_t->");
@@ -1164,22 +1159,27 @@ void Generator::generateStaticMetacall()
fprintf(out, "%s(", f.name.constData());
int offset = 1;
- int argsCount = f.arguments.count();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
- fprintf(out, ",");
- fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
- isUsed_a = true;
- }
- if (f.isPrivateSignal) {
- if (argsCount > 0)
- fprintf(out, ", ");
- fprintf(out, "%s", "QPrivateSignal()");
+ if (f.isRawSlot) {
+ fprintf(out, "QMethodRawArguments{ _a }");
+ } else {
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
+ fprintf(out, ",");
+ fprintf(out, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++);
+ isUsed_a = true;
+ }
+ if (f.isPrivateSignal) {
+ if (!f.arguments.isEmpty())
+ fprintf(out, ", ");
+ fprintf(out, "%s", "QPrivateSignal()");
+ }
}
fprintf(out, ");");
if (f.normalizedType != "void") {
- fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = _r; } ",
+ fprintf(out, "\n if (_a[0]) *reinterpret_cast< %s*>(_a[0]) = std::move(_r); } ",
noRef(f.normalizedType).constData());
isUsed_a = true;
}
@@ -1195,17 +1195,21 @@ void Generator::generateStaticMetacall()
if (!methodsWithAutomaticTypes.isEmpty()) {
fprintf(out, " else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {\n");
fprintf(out, " switch (_id) {\n");
- fprintf(out, " default: *reinterpret_cast<int*>(_a[0]) = -1; break;\n");
+ fprintf(out, " default: *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType(); break;\n");
QMap<int, QMultiMap<QByteArray, int> >::const_iterator it = methodsWithAutomaticTypes.constBegin();
const QMap<int, QMultiMap<QByteArray, int> >::const_iterator end = methodsWithAutomaticTypes.constEnd();
for ( ; it != end; ++it) {
fprintf(out, " case %d:\n", it.key());
fprintf(out, " switch (*reinterpret_cast<int*>(_a[1])) {\n");
- fprintf(out, " default: *reinterpret_cast<int*>(_a[0]) = -1; break;\n");
- for (const QByteArray &key : it->uniqueKeys()) {
- for (int argumentID : it->values(key))
- fprintf(out, " case %d:\n", argumentID);
- fprintf(out, " *reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< %s >(); break;\n", key.constData());
+ fprintf(out, " default: *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType(); break;\n");
+ auto jt = it->begin();
+ const auto jend = it->end();
+ while (jt != jend) {
+ fprintf(out, " case %d:\n", jt.value());
+ const QByteArray &lastKey = jt.key();
+ ++jt;
+ if (jt == jend || jt.key() != lastKey)
+ fprintf(out, " *reinterpret_cast<QMetaType *>(_a[0]) = QMetaType::fromType< %s >(); break;\n", lastKey.constData());
}
fprintf(out, " }\n");
fprintf(out, " break;\n");
@@ -1220,25 +1224,29 @@ void Generator::generateStaticMetacall()
Q_ASSERT(needElse); // if there is signal, there was method.
fprintf(out, " else if (_c == QMetaObject::IndexOfMethod) {\n");
fprintf(out, " int *result = reinterpret_cast<int *>(_a[0]);\n");
- fprintf(out, " void **func = reinterpret_cast<void **>(_a[1]);\n");
bool anythingUsed = false;
- for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) {
+ for (int methodindex = 0; methodindex < int(cdef->signalList.size()); ++methodindex) {
const FunctionDef &f = cdef->signalList.at(methodindex);
- if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic || f.mangledName.isEmpty())
+ if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic)
+ continue;
+ // -- QtScxml
+ if (f.mangledName.isEmpty())
continue;
+ // -- QtScxml
anythingUsed = true;
fprintf(out, " {\n");
- fprintf(out, " typedef %s (%s::*_t)(",f.type.rawName.constData() , cdef->classname.constData());
+ fprintf(out, " using _t = %s (%s::*)(",f.type.rawName.constData() , cdef->classname.constData());
- int argsCount = f.arguments.count();
- for (int j = 0; j < argsCount; ++j) {
- const ArgumentDef &a = f.arguments.at(j);
- if (j)
+ const auto begin = f.arguments.cbegin();
+ const auto end = f.arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
fprintf(out, ", ");
fprintf(out, "%s", QByteArray(a.type.name + ' ' + a.rightType).constData());
}
if (f.isPrivateSignal) {
- if (argsCount > 0)
+ if (!f.arguments.isEmpty())
fprintf(out, ", ");
fprintf(out, "%s", "QPrivateSignal");
}
@@ -1246,19 +1254,19 @@ void Generator::generateStaticMetacall()
fprintf(out, ") const;\n");
else
fprintf(out, ");\n");
- fprintf(out, " if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&%s::%s)) {\n",
- cdef->classname.constData(), f.mangledName.constData());
+ fprintf(out, " if (_t _q_method = &%s::%s; *reinterpret_cast<_t *>(_a[1]) == _q_method) {\n",
+ cdef->classname.constData(), f.mangledName.constData()); // -- QtScxml
fprintf(out, " *result = %d;\n", methodindex);
fprintf(out, " return;\n");
fprintf(out, " }\n }\n");
}
if (!anythingUsed)
- fprintf(out, " Q_UNUSED(result);\n Q_UNUSED(func);\n");
+ fprintf(out, " (void)result;\n");
fprintf(out, " }");
needElse = true;
}
- QMultiMap<QByteArray, int> automaticPropertyMetaTypes = automaticPropertyMetaTypesHelper();
+ const QMultiMap<QByteArray, int> automaticPropertyMetaTypes = automaticPropertyMetaTypesHelper();
if (!automaticPropertyMetaTypes.isEmpty()) {
if (needElse)
@@ -1268,13 +1276,17 @@ void Generator::generateStaticMetacall()
fprintf(out, "if (_c == QMetaObject::RegisterPropertyMetaType) {\n");
fprintf(out, " switch (_id) {\n");
fprintf(out, " default: *reinterpret_cast<int*>(_a[0]) = -1; break;\n");
- for (const QByteArray &key : automaticPropertyMetaTypes.uniqueKeys()) {
- for (int propertyID : automaticPropertyMetaTypes.values(key))
- fprintf(out, " case %d:\n", propertyID);
- fprintf(out, " *reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< %s >(); break;\n", key.constData());
+ auto it = automaticPropertyMetaTypes.begin();
+ const auto end = automaticPropertyMetaTypes.end();
+ while (it != end) {
+ fprintf(out, " case %d:\n", it.value());
+ const QByteArray &lastKey = it.key();
+ ++it;
+ if (it == end || it.key() != lastKey)
+ fprintf(out, " *reinterpret_cast<int*>(_a[0]) = qRegisterMetaType< %s >(); break;\n", lastKey.constData());
}
fprintf(out, " }\n");
- fprintf(out, " }\n");
+ fprintf(out, " } ");
isUsed_a = true;
needElse = true;
}
@@ -1284,8 +1296,8 @@ void Generator::generateStaticMetacall()
bool needTempVarForGet = false;
bool needSet = false;
bool needReset = false;
- for (int i = 0; i < cdef->propertyList.size(); ++i) {
- const PropertyDef &p = cdef->propertyList.at(i);
+ bool hasBindableProperties = false;
+ for (const PropertyDef &p : std::as_const(cdef->propertyList)) {
needGet |= !p.read.isEmpty() || !p.member.isEmpty();
if (!p.read.isEmpty() || !p.member.isEmpty())
needTempVarForGet |= (p.gspec != PropertyDef::PointerSpec
@@ -1293,26 +1305,30 @@ void Generator::generateStaticMetacall()
needSet |= !p.write.isEmpty() || (!p.member.isEmpty() && !p.constant);
needReset |= !p.reset.isEmpty();
+ hasBindableProperties |= !p.bind.isEmpty();
}
- fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n ");
-
if (needElse)
- fprintf(out, "else ");
+ fprintf(out, " else ");
fprintf(out, "if (_c == QMetaObject::ReadProperty) {\n");
- if (needGet) {
+
+ auto setupMemberAccess = [this]() {
if (cdef->hasQObject) {
#ifndef QT_NO_DEBUG
fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n");
#endif
- fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
+ fprintf(out, " auto *_t = static_cast<%s *>(_o);\n", cdef->classname.constData());
} else {
- fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
+ fprintf(out, " auto *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData());
}
- fprintf(out, " Q_UNUSED(_t)\n");
+ fprintf(out, " (void)_t;\n");
+ };
+
+ if (needGet) {
+ setupMemberAccess();
if (needTempVarForGet)
fprintf(out, " void *_v = _a[0];\n");
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.read.isEmpty() && p.member.isEmpty())
continue;
@@ -1320,6 +1336,7 @@ void Generator::generateStaticMetacall()
if (p.inPrivateClass.size()) {
prefix += p.inPrivateClass + "->";
}
+
if (p.gspec == PropertyDef::PointerSpec)
fprintf(out, " case %d: _a[0] = const_cast<void*>(reinterpret_cast<const void*>(%s%s())); break;\n",
propindex, prefix.constData(), p.read.constData());
@@ -1329,14 +1346,15 @@ void Generator::generateStaticMetacall()
else if (cdef->enumDeclarations.value(p.type, false))
fprintf(out, " case %d: *reinterpret_cast<int*>(_v) = QFlag(%s%s()); break;\n",
propindex, prefix.constData(), p.read.constData());
+ else if (p.read == "default")
+ fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s().value(); break;\n",
+ propindex, p.type.constData(), prefix.constData(), p.bind.constData());
else if (!p.read.isEmpty())
- //---- Changed from the original in moc
- {
- fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s%s; break;\n",
- propindex, p.type.constData(), prefix.constData(), p.read.constData(),
- p.read.endsWith(')') ? "" : "()");
- }
- //---- End of change
+ // -- QtScxml
+ fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s%s; break;\n",
+ propindex, p.type.constData(), prefix.constData(), p.read.constData(),
+ p.read.endsWith(')') ? "" : "()");
+ // -- QtScxml
else
fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n",
propindex, p.type.constData(), prefix.constData(), p.member.constData());
@@ -1351,18 +1369,10 @@ void Generator::generateStaticMetacall()
fprintf(out, "if (_c == QMetaObject::WriteProperty) {\n");
if (needSet) {
- if (cdef->hasQObject) {
-#ifndef QT_NO_DEBUG
- fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n");
-#endif
- fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
- } else {
- fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
- }
- fprintf(out, " Q_UNUSED(_t)\n");
+ setupMemberAccess();
fprintf(out, " void *_v = _a[0];\n");
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
if (p.constant)
continue;
@@ -1375,6 +1385,12 @@ void Generator::generateStaticMetacall()
if (cdef->enumDeclarations.value(p.type, false)) {
fprintf(out, " case %d: %s%s(QFlag(*reinterpret_cast<int*>(_v))); break;\n",
propindex, prefix.constData(), p.write.constData());
+ } else if (p.write == "default") {
+ fprintf(out, " case %d: {\n", propindex);
+ fprintf(out, " %s%s().setValue(*reinterpret_cast< %s*>(_v));\n",
+ prefix.constData(), p.bind.constData(), p.type.constData());
+ fprintf(out, " break;\n");
+ fprintf(out, " }\n");
} else if (!p.write.isEmpty()) {
fprintf(out, " case %d: %s%s(*reinterpret_cast< %s*>(_v)); break;\n",
propindex, prefix.constData(), p.write.constData(), p.type.constData());
@@ -1384,13 +1400,15 @@ void Generator::generateStaticMetacall()
prefix.constData(), p.member.constData(), p.type.constData());
fprintf(out, " %s%s = *reinterpret_cast< %s*>(_v);\n",
prefix.constData(), p.member.constData(), p.type.constData());
- if (!p.notify.isEmpty() && p.notifyId != -1) {
+ if (!p.notify.isEmpty() && p.notifyId > -1) {
const FunctionDef &f = cdef->signalList.at(p.notifyId);
if (f.arguments.size() == 0)
fprintf(out, " Q_EMIT _t->%s();\n", p.notify.constData());
else if (f.arguments.size() == 1 && f.arguments.at(0).normalizedType == p.type)
fprintf(out, " Q_EMIT _t->%s(%s%s);\n",
p.notify.constData(), prefix.constData(), p.member.constData());
+ } else if (!p.notify.isEmpty() && p.notifyId < -1) {
+ fprintf(out, " Q_EMIT _t->%s();\n", p.notify.constData());
}
fprintf(out, " }\n");
fprintf(out, " break;\n");
@@ -1405,32 +1423,46 @@ void Generator::generateStaticMetacall()
fprintf(out, " else ");
fprintf(out, "if (_c == QMetaObject::ResetProperty) {\n");
if (needReset) {
- if (cdef->hasQObject) {
-#ifndef QT_NO_DEBUG
- fprintf(out, " Q_ASSERT(staticMetaObject.cast(_o));\n");
-#endif
- fprintf(out, " %s *_t = static_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
- } else {
- fprintf(out, " %s *_t = reinterpret_cast<%s *>(_o);\n", cdef->classname.constData(), cdef->classname.constData());
- }
- fprintf(out, " Q_UNUSED(_t)\n");
+ setupMemberAccess();
fprintf(out, " switch (_id) {\n");
- for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
const PropertyDef &p = cdef->propertyList.at(propindex);
- if (!p.reset.endsWith(')'))
+ if (p.reset.isEmpty())
continue;
QByteArray prefix = "_t->";
if (p.inPrivateClass.size()) {
prefix += p.inPrivateClass + "->";
}
- fprintf(out, " case %d: %s%s; break;\n",
+ fprintf(out, " case %d: %s%s(); break;\n",
propindex, prefix.constData(), p.reset.constData());
}
fprintf(out, " default: break;\n");
fprintf(out, " }\n");
}
fprintf(out, " }");
- fprintf(out, "\n#endif // QT_NO_PROPERTIES");
+
+ fprintf(out, " else ");
+ fprintf(out, "if (_c == QMetaObject::BindableProperty) {\n");
+ if (hasBindableProperties) {
+ setupMemberAccess();
+ fprintf(out, " switch (_id) {\n");
+ for (int propindex = 0; propindex < int(cdef->propertyList.size()); ++propindex) {
+ const PropertyDef &p = cdef->propertyList.at(propindex);
+ if (p.bind.isEmpty())
+ continue;
+ QByteArray prefix = "_t->";
+ if (p.inPrivateClass.size()) {
+ prefix += p.inPrivateClass + "->";
+ }
+ fprintf(out,
+ " case %d: *static_cast<QUntypedBindable *>(_a[0]) = %s%s(); "
+ "break;\n",
+ propindex, prefix.constData(), p.bind.constData());
+ }
+ fprintf(out, " default: break;\n");
+ fprintf(out, " }\n");
+ }
+ fprintf(out, " }");
needElse = true;
}
@@ -1438,22 +1470,26 @@ void Generator::generateStaticMetacall()
fprintf(out, "\n");
if (methodList.isEmpty()) {
- fprintf(out, " Q_UNUSED(_o);\n");
+ fprintf(out, " (void)_o;\n");
if (cdef->constructorList.isEmpty() && automaticPropertyMetaTypes.isEmpty() && methodsWithAutomaticTypesHelper(methodList).isEmpty()) {
- fprintf(out, " Q_UNUSED(_id);\n");
- fprintf(out, " Q_UNUSED(_c);\n");
+ fprintf(out, " (void)_id;\n");
+ fprintf(out, " (void)_c;\n");
}
}
if (!isUsed_a)
- fprintf(out, " Q_UNUSED(_a);\n");
+ fprintf(out, " (void)_a;\n");
- fprintf(out, "}\n\n");
+ fprintf(out, "}\n");
}
-void Generator::generateSignal(FunctionDef *def,int index)
+void Generator::generateSignal(const FunctionDef *def, int index)
{
- if (def->wasCloned || def->isAbstract || def->implementation)
+ if (def->wasCloned || def->isAbstract)
+ return;
+// -- QtScxml
+ if (def->implementation)
return;
+// -- QtScxml
fprintf(out, "\n// SIGNAL %d\n%s %s::%s(",
index, def->type.name.constData(), cdef->qualified.constData(), def->name.constData());
@@ -1461,17 +1497,12 @@ void Generator::generateSignal(FunctionDef *def,int index)
const char *constQualifier = "";
if (def->isConst) {
- thisPtr = "const_cast< ";
- thisPtr += cdef->qualified;
- thisPtr += " *>(this)";
+ thisPtr = "const_cast< " + cdef->qualified + " *>(this)";
constQualifier = "const";
}
Q_ASSERT(!def->normalizedType.isEmpty());
- if (def->arguments.isEmpty() && def->normalizedType == "void") {
- if (def->isPrivateSignal)
- fprintf(out, "QPrivateSignal");
-
+ if (def->arguments.isEmpty() && def->normalizedType == "void" && !def->isPrivateSignal) {
fprintf(out, ")%s\n{\n"
" QMetaObject::activate(%s, &staticMetaObject, %d, nullptr);\n"
"}\n", constQualifier, thisPtr.constData(), index);
@@ -1479,40 +1510,43 @@ void Generator::generateSignal(FunctionDef *def,int index)
}
int offset = 1;
- for (int j = 0; j < def->arguments.count(); ++j) {
- const ArgumentDef &a = def->arguments.at(j);
- if (j)
- fprintf(out, ", ");
- fprintf(out, "%s _t%d%s", a.type.name.constData(), offset++, a.rightType.constData());
+ const auto begin = def->arguments.cbegin();
+ const auto end = def->arguments.cend();
+ for (auto it = begin; it != end; ++it) {
+ const ArgumentDef &a = *it;
+ if (it != begin)
+ fputs(", ", out);
+ if (a.type.name.size())
+ fputs(a.type.name.constData(), out);
+ fprintf(out, " _t%d", offset++);
+ if (a.rightType.size())
+ fputs(a.rightType.constData(), out);
}
if (def->isPrivateSignal) {
if (!def->arguments.isEmpty())
fprintf(out, ", ");
- fprintf(out, "QPrivateSignal");
+ fprintf(out, "QPrivateSignal _t%d", offset++);
}
fprintf(out, ")%s\n{\n", constQualifier);
if (def->type.name.size() && def->normalizedType != "void") {
QByteArray returnType = noRef(def->normalizedType);
- if (returnType.endsWith('*')) {
- fprintf(out, " %s _t0 = 0;\n", returnType.constData());
- } else {
- fprintf(out, " %s _t0 = %s();\n", returnType.constData(), returnType.constData());
- }
+ fprintf(out, " %s _t0{};\n", returnType.constData());
}
fprintf(out, " void *_a[] = { ");
if (def->normalizedType == "void") {
fprintf(out, "nullptr");
} else {
- fprintf(out, "const_cast<void*>(reinterpret_cast<const void*>(&_t0))");
+ // -- QtScxml removed unused returnTypeIsVolatile
+ fprintf(out, "const_cast<void*>(reinterpret_cast<const void*>(std::addressof(_t0)))");
}
int i;
for (i = 1; i < offset; ++i)
- if (def->arguments.at(i - 1).type.isVolatile)
- fprintf(out, ", const_cast<void*>(reinterpret_cast<const volatile void*>(&_t%d))", i);
+ if (i <= def->arguments.size() && def->arguments.at(i - 1).type.isVolatile)
+ fprintf(out, ", const_cast<void*>(reinterpret_cast<const volatile void*>(std::addressof(_t%d)))", i);
else
- fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(&_t%d))", i);
+ fprintf(out, ", const_cast<void*>(reinterpret_cast<const void*>(std::addressof(_t%d)))", i);
fprintf(out, " };\n");
fprintf(out, " QMetaObject::activate(%s, &staticMetaObject, %d, _a);\n", thisPtr.constData(), index);
if (def->normalizedType != "void")
@@ -1520,6 +1554,7 @@ void Generator::generateSignal(FunctionDef *def,int index)
fprintf(out, "}\n");
}
+// -- QtScxml
void Generator::generateAccessorDefs()
{
for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
@@ -1549,31 +1584,55 @@ void Generator::generateSignalDefs()
}
#if 0
-static void writePluginMetaData(FILE *out, const QJsonObject &data)
+static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v);
+static CborError jsonObjectToCbor(CborEncoder *parent, const QJsonObject &o)
{
- const QJsonDocument doc(data);
+ auto it = o.constBegin();
+ auto end = o.constEnd();
+ CborEncoder map;
+ cbor_encoder_create_map(parent, &map, o.size());
+
+ for ( ; it != end; ++it) {
+ QByteArray key = it.key().toUtf8();
+ cbor_encode_text_string(&map, key.constData(), key.size());
+ jsonValueToCbor(&map, it.value());
+ }
+ return cbor_encoder_close_container(parent, &map);
+}
- fputs("\nQT_PLUGIN_METADATA_SECTION\n"
- "static const unsigned char qt_pluginMetaData[] = {\n"
- " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', ' ',\n ", out);
-#if 0
- fprintf(out, "\"%s\";\n", doc.toJson().constData());
-#else
- const QByteArray binary = doc.toBinaryData();
- const int last = binary.size() - 1;
- for (int i = 0; i < last; ++i) {
- uchar c = (uchar)binary.at(i);
- if (c < 0x20 || c >= 0x7f)
- fprintf(out, " 0x%02x,", c);
- else if (c == '\'' || c == '\\')
- fprintf(out, " '\\%c',", c);
- else
- fprintf(out, " '%c', ", c);
- if (!((i + 1) % 8))
- fputs("\n ", out);
+static CborError jsonArrayToCbor(CborEncoder *parent, const QJsonArray &a)
+{
+ CborEncoder array;
+ cbor_encoder_create_array(parent, &array, a.size());
+ for (const QJsonValue v : a)
+ jsonValueToCbor(&array, v);
+ return cbor_encoder_close_container(parent, &array);
+}
+
+static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v)
+{
+ switch (v.type()) {
+ case QJsonValue::Null:
+ case QJsonValue::Undefined:
+ return cbor_encode_null(parent);
+ case QJsonValue::Bool:
+ return cbor_encode_boolean(parent, v.toBool());
+ case QJsonValue::Array:
+ return jsonArrayToCbor(parent, v.toArray());
+ case QJsonValue::Object:
+ return jsonObjectToCbor(parent, v.toObject());
+ case QJsonValue::String: {
+ QByteArray s = v.toString().toUtf8();
+ return cbor_encode_text_string(parent, s.constData(), s.size());
}
- fprintf(out, " 0x%02x\n};\n", (uchar)binary.at(last));
-#endif
+ case QJsonValue::Double: {
+ double d = v.toDouble();
+ if (d == floor(d) && fabs(d) <= (Q_INT64_C(1) << std::numeric_limits<double>::digits))
+ return cbor_encode_int(parent, qint64(d));
+ return cbor_encode_double(parent, d);
+ }
+ }
+ Q_UNREACHABLE_RETURN(CborUnknownError);
}
void Generator::generatePluginMetaData()
@@ -1581,40 +1640,90 @@ void Generator::generatePluginMetaData()
if (cdef->pluginData.iid.isEmpty())
return;
- // Write plugin meta data #ifdefed QT_NO_DEBUG with debug=false,
- // true, respectively.
+ auto outputCborData = [this]() {
+ CborDevice dev(out);
+ CborEncoder enc;
+ cbor_encoder_init_writer(&enc, CborDevice::callback, &dev);
- QJsonObject data;
- const QString debugKey = QStringLiteral("debug");
- data.insert(QStringLiteral("IID"), QLatin1String(cdef->pluginData.iid.constData()));
- data.insert(QStringLiteral("className"), QLatin1String(cdef->classname.constData()));
- data.insert(QStringLiteral("version"), (int)QT_VERSION);
- data.insert(debugKey, QJsonValue(false));
- data.insert(QStringLiteral("MetaData"), cdef->pluginData.metaData.object());
+ CborEncoder map;
+ cbor_encoder_create_map(&enc, &map, CborIndefiniteLength);
- // Add -M args from the command line:
- for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it)
- data.insert(it.key(), it.value());
+ dev.nextItem("\"IID\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID));
+ cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size());
- fputs("\nQT_PLUGIN_METADATA_SECTION const uint qt_section_alignment_dummy = 42;\n\n"
- "#ifdef QT_NO_DEBUG\n", out);
- writePluginMetaData(out, data);
+ dev.nextItem("\"className\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName));
+ cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size());
- fputs("\n#else // QT_NO_DEBUG\n", out);
+ QJsonObject o = cdef->pluginData.metaData.object();
+ if (!o.isEmpty()) {
+ dev.nextItem("\"MetaData\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData));
+ jsonObjectToCbor(&map, o);
+ }
- data.remove(debugKey);
- data.insert(debugKey, QJsonValue(true));
- writePluginMetaData(out, data);
+ if (!cdef->pluginData.uri.isEmpty()) {
+ dev.nextItem("\"URI\"");
+ cbor_encode_int(&map, int(QtPluginMetaDataKeys::URI));
+ cbor_encode_text_string(&map, cdef->pluginData.uri.constData(), cdef->pluginData.uri.size());
+ }
- fputs("#endif // QT_NO_DEBUG\n\n", out);
+ // Add -M args from the command line:
+ for (auto it = cdef->pluginData.metaArgs.cbegin(), end = cdef->pluginData.metaArgs.cend(); it != end; ++it) {
+ const QJsonArray &a = it.value();
+ QByteArray key = it.key().toUtf8();
+ dev.nextItem(QByteArray("command-line \"" + key + "\"").constData());
+ cbor_encode_text_string(&map, key.constData(), key.size());
+ jsonArrayToCbor(&map, a);
+ }
+
+ // Close the CBOR map manually
+ dev.nextItem();
+ cbor_encoder_close_container(&enc, &map);
+ };
// 'Use' all namespaces.
- int pos = cdef->qualified.indexOf("::");
+ qsizetype pos = cdef->qualified.indexOf("::");
for ( ; pos != -1 ; pos = cdef->qualified.indexOf("::", pos + 2) )
fprintf(out, "using namespace %s;\n", cdef->qualified.left(pos).constData());
- fprintf(out, "QT_MOC_EXPORT_PLUGIN(%s, %s)\n\n",
+
+ fputs("\n#ifdef QT_MOC_EXPORT_PLUGIN_V2", out);
+
+ // Qt 6.3+ output
+ fprintf(out, "\nstatic constexpr unsigned char qt_pluginMetaDataV2_%s[] = {",
+ cdef->classname.constData());
+ outputCborData();
+ fprintf(out, "\n};\nQT_MOC_EXPORT_PLUGIN_V2(%s, %s, qt_pluginMetaDataV2_%s)\n",
+ cdef->qualified.constData(), cdef->classname.constData(), cdef->classname.constData());
+
+ // compatibility with Qt 6.0-6.2
+ fprintf(out, "#else\nQT_PLUGIN_METADATA_SECTION\n"
+ "Q_CONSTINIT static constexpr unsigned char qt_pluginMetaData_%s[] = {\n"
+ " 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!',\n"
+ " // metadata version, Qt version, architectural requirements\n"
+ " 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(),",
+ cdef->classname.constData());
+ outputCborData();
+ fprintf(out, "\n};\nQT_MOC_EXPORT_PLUGIN(%s, %s)\n"
+ "#endif // QT_MOC_EXPORT_PLUGIN_V2\n",
cdef->qualified.constData(), cdef->classname.constData());
+
+ fputs("\n", out);
}
+
+QT_WARNING_DISABLE_GCC("-Wunused-function")
+QT_WARNING_DISABLE_CLANG("-Wunused-function")
+QT_WARNING_DISABLE_CLANG("-Wundefined-internal")
+QT_WARNING_DISABLE_MSVC(4334) // '<<': result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
+
+#define CBOR_ENCODER_WRITER_CONTROL 1
+#define CBOR_ENCODER_WRITE_FUNCTION CborDevice::callback
#endif
+// -- QtScxml
QT_END_NAMESPACE
+
+#if 0 // -- QtScxml
+#include "cborencoder.c"
+#endif // -- QtScxml
diff --git a/tools/qscxmlc/generator.h b/tools/qscxmlc/generator.h
index e1f10eb..8db1350 100644
--- a/tools/qscxmlc/generator.h
+++ b/tools/qscxmlc/generator.h
@@ -1,60 +1,47 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef GENERATOR_H
#define GENERATOR_H
#include "moc.h"
+
+// -- QtScxml
#include <QtCore/qhash.h>
-#include <QtCore/qvector.h>
+#include <QtCore/qlist.h>
#include <QtCore/qiodevice.h>
+// -- QtScxml
QT_BEGIN_NAMESPACE
class Generator
{
- QIODevice &out;
+ QIODevice &out; // -- QtScxml
ClassDef *cdef;
- QVector<uint> meta_data;
+ QList<uint> meta_data;
+
public:
- Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, const QHash<QByteArray,
- QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets,
- QIODevice &outfile);
+ Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ const QHash<QByteArray, QByteArray> &knownQObjectClasses,
+ const QHash<QByteArray, QByteArray> &knownGadgets,
+ QIODevice &outfile, // -- QtScxml
+ bool requireCompleteTypes = false);
void generateCode();
+ qsizetype registeredStringsCount() { return strings.size(); };
+
+// -- QtScxml
void generateAccessorDefs();
void generateSignalDefs();
+// -- QtScxml
private:
bool registerableMetaType(const QByteArray &propertyType);
void registerClassInfoStrings();
void generateClassInfos();
void registerFunctionStrings(const QList<FunctionDef> &list);
- void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type, int &paramsIndex);
+ void registerByteArrayVector(const QList<QByteArray> &list);
+ void generateFunctions(const QList<FunctionDef> &list, const char *functype, int type,
+ int &paramsIndex, int &initialMetatypeOffset);
void generateFunctionRevisions(const QList<FunctionDef> &list, const char *functype);
void generateFunctionParameters(const QList<FunctionDef> &list, const char *functype);
void generateTypeInfo(const QByteArray &typeName, bool allowEmptyName = false);
@@ -64,10 +51,13 @@ private:
void generateProperties();
void generateMetacall();
void generateStaticMetacall();
- void generateSignal(FunctionDef *def, int index);
-// void generatePluginMetaData();
+ void generateSignal(const FunctionDef *def, int index);
+#if 0 // -- QtScxml
+ void generatePluginMetaData();
+#endif // -- QtScxml
QMultiMap<QByteArray, int> automaticPropertyMetaTypesHelper();
- QMap<int, QMultiMap<QByteArray, int> > methodsWithAutomaticTypesHelper(const QList<FunctionDef> &methodList);
+ QMap<int, QMultiMap<QByteArray, int>>
+ methodsWithAutomaticTypesHelper(const QList<FunctionDef> &methodList);
void strreg(const QByteArray &); // registers a string
int stridx(const QByteArray &); // returns a string's id
@@ -76,6 +66,7 @@ private:
QList<QByteArray> metaTypes;
QHash<QByteArray, QByteArray> knownQObjectClasses;
QHash<QByteArray, QByteArray> knownGadgets;
+ bool requireCompleteTypes;
};
QT_END_NAMESPACE
diff --git a/tools/qscxmlc/main.cpp b/tools/qscxmlc/main.cpp
index ccc99ed..9e09dbf 100644
--- a/tools/qscxmlc/main.cpp
+++ b/tools/qscxmlc/main.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtScxml/qscxmltabledata.h>
#include "qscxmlc.h"
diff --git a/tools/qscxmlc/moc.cpp b/tools/qscxmlc/moc.cpp
new file mode 100644
index 0000000..aeb3cad
--- /dev/null
+++ b/tools/qscxmlc/moc.cpp
@@ -0,0 +1,2215 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "moc.h"
+#include "generator.h"
+#include "qdatetime.h"
+#include "utils.h"
+#include "outputrevision.h"
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qdir.h>
+#include <QtCore/qjsondocument.h>
+
+// -- QtScxml
+#include <QtCore/qjsonobject.h>
+// -- QtScxml
+
+QT_BEGIN_NAMESPACE
+
+using namespace Qt::StringLiterals;
+
+#if 0 // -- QtScxml
+// only moc needs this function
+static QByteArray normalizeType(const QByteArray &ba)
+{
+ return ba.size() ? normalizeTypeInternal(ba.constBegin(), ba.constEnd()) : ba;
+}
+
+const QByteArray &Moc::toFullyQualified(const QByteArray &name) const noexcept
+{
+ if (auto it = knownQObjectClasses.find(name); it != knownQObjectClasses.end())
+ return it.value();
+ if (auto it = knownGadgets.find(name); it != knownGadgets.end())
+ return it.value();
+ return name;
+}
+
+bool Moc::parseClassHead(ClassDef *def)
+{
+ // figure out whether this is a class declaration, or only a
+ // forward or variable declaration.
+ int i = 0;
+ Token token;
+ do {
+ token = lookup(i++);
+ if (token == COLON || token == LBRACE)
+ break;
+ if (token == SEMIC || token == RANGLE)
+ return false;
+ } while (token);
+
+ // support attributes like "class [[deprecated]]] name"
+ skipCxxAttributes();
+
+ if (!test(IDENTIFIER)) // typedef struct { ... }
+ return false;
+ QByteArray name = lexem();
+
+ // support "class IDENT name" and "class IDENT(IDENT) name"
+ // also support "class IDENT name (final|sealed|Q_DECL_FINAL)"
+ if (test(LPAREN)) {
+ until(RPAREN);
+ if (!test(IDENTIFIER))
+ return false;
+ name = lexem();
+ } else if (test(IDENTIFIER)) {
+ const QByteArray lex = lexem();
+ if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL")
+ name = lex;
+ }
+
+ def->qualified += name;
+ while (test(SCOPE)) {
+ def->qualified += lexem();
+ if (test(IDENTIFIER)) {
+ name = lexem();
+ def->qualified += name;
+ }
+ }
+ def->classname = name;
+
+ if (test(IDENTIFIER)) {
+ const QByteArray lex = lexem();
+ if (lex != "final" && lex != "sealed" && lex != "Q_DECL_FINAL")
+ return false;
+ }
+
+ if (test(COLON)) {
+ do {
+ test(VIRTUAL);
+ FunctionDef::Access access = FunctionDef::Public;
+ if (test(PRIVATE))
+ access = FunctionDef::Private;
+ else if (test(PROTECTED))
+ access = FunctionDef::Protected;
+ else
+ test(PUBLIC);
+ test(VIRTUAL);
+ const Type type = parseType();
+ // ignore the 'class Foo : BAR(Baz)' case
+ if (test(LPAREN)) {
+ until(RPAREN);
+ } else {
+ def->superclassList.push_back({type.name, toFullyQualified(type.name), access});
+ }
+ } while (test(COMMA));
+
+ if (!def->superclassList.isEmpty()
+ && knownGadgets.contains(def->superclassList.constFirst().classname)) {
+ // Q_GADGET subclasses are treated as Q_GADGETs
+ knownGadgets.insert(def->classname, def->qualified);
+ knownGadgets.insert(def->qualified, def->qualified);
+ }
+ }
+ if (!test(LBRACE))
+ return false;
+ def->begin = index - 1;
+ bool foundRBrace = until(RBRACE);
+ def->end = index;
+ index = def->begin + 1;
+ return foundRBrace;
+}
+
+Type Moc::parseType()
+{
+ Type type;
+ bool hasSignedOrUnsigned = false;
+ bool isVoid = false;
+ type.firstToken = lookup();
+ for (;;) {
+ skipCxxAttributes();
+ switch (next()) {
+ case SIGNED:
+ case UNSIGNED:
+ hasSignedOrUnsigned = true;
+ Q_FALLTHROUGH();
+ case CONST:
+ case VOLATILE:
+ type.name += lexem();
+ type.name += ' ';
+ if (lookup(0) == VOLATILE)
+ type.isVolatile = true;
+ continue;
+ case Q_MOC_COMPAT_TOKEN:
+ case Q_INVOKABLE_TOKEN:
+ case Q_SCRIPTABLE_TOKEN:
+ case Q_SIGNALS_TOKEN:
+ case Q_SLOTS_TOKEN:
+ case Q_SIGNAL_TOKEN:
+ case Q_SLOT_TOKEN:
+ type.name += lexem();
+ return type;
+ case NOTOKEN:
+ return type;
+ default:
+ prev();
+ break;
+ }
+ break;
+ }
+
+ skipCxxAttributes();
+ test(ENUM) || test(CLASS) || test(STRUCT);
+ for(;;) {
+ skipCxxAttributes();
+ switch (next()) {
+ case IDENTIFIER:
+ // void mySlot(unsigned myArg)
+ if (hasSignedOrUnsigned) {
+ prev();
+ break;
+ }
+ Q_FALLTHROUGH();
+ case CHAR:
+ case SHORT:
+ case INT:
+ case LONG:
+ type.name += lexem();
+ // preserve '[unsigned] long long', 'short int', 'long int', 'long double'
+ if (test(LONG) || test(INT) || test(DOUBLE)) {
+ type.name += ' ';
+ prev();
+ continue;
+ }
+ break;
+ case FLOAT:
+ case DOUBLE:
+ case VOID:
+ case BOOL:
+ case AUTO:
+ type.name += lexem();
+ isVoid |= (lookup(0) == VOID);
+ break;
+ case NOTOKEN:
+ return type;
+ default:
+ prev();
+ ;
+ }
+ if (test(LANGLE)) {
+ if (type.name.isEmpty()) {
+ // '<' cannot start a type
+ return type;
+ }
+ type.name += lexemUntil(RANGLE);
+ }
+ if (test(SCOPE)) {
+ type.name += lexem();
+ type.isScoped = true;
+ } else {
+ break;
+ }
+ }
+ while (test(CONST) || test(VOLATILE) || test(SIGNED) || test(UNSIGNED)
+ || test(STAR) || test(AND) || test(ANDAND)) {
+ type.name += ' ';
+ type.name += lexem();
+ if (lookup(0) == AND)
+ type.referenceType = Type::Reference;
+ else if (lookup(0) == ANDAND)
+ type.referenceType = Type::RValueReference;
+ else if (lookup(0) == STAR)
+ type.referenceType = Type::Pointer;
+ }
+ type.rawName = type.name;
+ // transform stupid things like 'const void' or 'void const' into 'void'
+ if (isVoid && type.referenceType == Type::NoReference) {
+ type.name = "void";
+ }
+ return type;
+}
+
+enum class IncludeState {
+ IncludeBegin,
+ IncludeEnd,
+ NoInclude,
+};
+
+bool Moc::parseEnum(EnumDef *def)
+{
+ bool isTypdefEnum = false; // typedef enum { ... } Foo;
+
+ if (test(CLASS) || test(STRUCT))
+ def->isEnumClass = true;
+
+ if (test(IDENTIFIER)) {
+ def->name = lexem();
+ } else {
+ if (lookup(-1) != TYPEDEF)
+ return false; // anonymous enum
+ isTypdefEnum = true;
+ }
+ if (test(COLON)) { // C++11 strongly typed enum
+ // enum Foo : unsigned long { ... };
+ def->type = normalizeType(parseType().name);
+ }
+ if (!test(LBRACE))
+ return false;
+ auto handleInclude = [this]() -> IncludeState {
+ bool hadIncludeBegin = false;
+ if (test(MOC_INCLUDE_BEGIN)) {
+ currentFilenames.push(symbol().unquotedLexem());
+ // we do not return early to handle empty headers in one go
+ hadIncludeBegin = true;
+ }
+ if (test(NOTOKEN)) {
+ next(MOC_INCLUDE_END);
+ currentFilenames.pop();
+ return IncludeState::IncludeEnd;
+ }
+ if (hadIncludeBegin)
+ return IncludeState::IncludeBegin;
+ else
+ return IncludeState::NoInclude;
+ };
+ do {
+ handleInclude();
+ if (lookup() == RBRACE) // accept trailing comma
+ break;
+ next(IDENTIFIER);
+ def->values += lexem();
+ handleInclude();
+ skipCxxAttributes();
+ } while (test(EQ) ? until(COMMA) : test(COMMA));
+ next(RBRACE);
+ if (isTypdefEnum) {
+ if (!test(IDENTIFIER))
+ return false;
+ def->name = lexem();
+ }
+ return true;
+}
+
+void Moc::parseFunctionArguments(FunctionDef *def)
+{
+ Q_UNUSED(def);
+ while (hasNext()) {
+ ArgumentDef arg;
+ arg.type = parseType();
+ if (arg.type.name == "void")
+ break;
+ if (test(IDENTIFIER))
+ arg.name = lexem();
+ while (test(LBRACK)) {
+ arg.rightType += lexemUntil(RBRACK);
+ }
+ if (test(CONST) || test(VOLATILE)) {
+ arg.rightType += ' ';
+ arg.rightType += lexem();
+ }
+ arg.normalizedType = normalizeType(QByteArray(arg.type.name + ' ' + arg.rightType));
+ arg.typeNameForCast = QByteArray("std::add_pointer_t<"+arg.normalizedType+">");
+ if (test(EQ))
+ arg.isDefault = true;
+ def->arguments += arg;
+ if (!until(COMMA))
+ break;
+ }
+
+ if (!def->arguments.isEmpty()
+ && def->arguments.constLast().normalizedType == "QPrivateSignal") {
+ def->arguments.removeLast();
+ def->isPrivateSignal = true;
+ }
+ if (def->arguments.size() == 1
+ && def->arguments.constLast().normalizedType == "QMethodRawArguments") {
+ def->arguments.removeLast();
+ def->isRawSlot = true;
+ }
+
+ if (Q_UNLIKELY(def->arguments.size() >= std::numeric_limits<int>::max()))
+ error("number of function arguments exceeds std::numeric_limits<int>::max()");
+}
+
+bool Moc::testFunctionAttribute(FunctionDef *def)
+{
+ if (index < symbols.size() && testFunctionAttribute(symbols.at(index).token, def)) {
+ ++index;
+ return true;
+ }
+ return false;
+}
+
+bool Moc::testFunctionAttribute(Token tok, FunctionDef *def)
+{
+ switch (tok) {
+ case Q_MOC_COMPAT_TOKEN:
+ def->isCompat = true;
+ return true;
+ case Q_INVOKABLE_TOKEN:
+ def->isInvokable = true;
+ return true;
+ case Q_SIGNAL_TOKEN:
+ def->isSignal = true;
+ return true;
+ case Q_SLOT_TOKEN:
+ def->isSlot = true;
+ return true;
+ case Q_SCRIPTABLE_TOKEN:
+ def->isInvokable = def->isScriptable = true;
+ return true;
+ default: break;
+ }
+ return false;
+}
+
+bool Moc::skipCxxAttributes()
+{
+ auto rewind = index;
+ if (test(LBRACK) && test(LBRACK) && until(RBRACK) && test(RBRACK))
+ return true;
+ index = rewind;
+ return false;
+}
+
+QTypeRevision Moc::parseRevision()
+{
+ next(LPAREN);
+ QByteArray revisionString = lexemUntil(RPAREN);
+ revisionString.remove(0, 1);
+ revisionString.chop(1);
+ const QList<QByteArray> majorMinor = revisionString.split(',');
+ switch (majorMinor.size()) {
+ case 1: {
+ bool ok = false;
+ const int revision = revisionString.toInt(&ok);
+ if (!ok || !QTypeRevision::isValidSegment(revision))
+ error("Invalid revision");
+ return QTypeRevision::fromMinorVersion(revision);
+ }
+ case 2: { // major.minor
+ bool ok = false;
+ const int major = majorMinor[0].toInt(&ok);
+ if (!ok || !QTypeRevision::isValidSegment(major))
+ error("Invalid major version");
+ const int minor = majorMinor[1].toInt(&ok);
+ if (!ok || !QTypeRevision::isValidSegment(minor))
+ error("Invalid minor version");
+ return QTypeRevision::fromVersion(major, minor);
+ }
+ default:
+ error("Invalid revision");
+ return QTypeRevision();
+ }
+}
+
+bool Moc::testFunctionRevision(FunctionDef *def)
+{
+
+ if (test(Q_REVISION_TOKEN)) {
+ def->revision = parseRevision().toEncodedVersion<int>();
+ return true;
+ }
+
+ return false;
+}
+
+// returns false if the function should be ignored
+bool Moc::parseFunction(FunctionDef *def, bool inMacro)
+{
+ def->isVirtual = false;
+ def->isStatic = false;
+ //skip modifiers and attributes
+ while (testForFunctionModifiers(def)
+ || skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
+ bool templateFunction = (lookup() == TEMPLATE);
+ def->type = parseType();
+ if (def->type.name.isEmpty()) {
+ if (templateFunction)
+ error("Template function as signal or slot");
+ else
+ error();
+ }
+ bool scopedFunctionName = false;
+ // we might have modifiers and attributes after a tag
+ // note that testFunctionAttribute is handled further below,
+ // and revisions and attributes must come first
+ while (testForFunctionModifiers(def)) {}
+ Type tempType = parseType();;
+ while (!tempType.name.isEmpty() && lookup() != LPAREN) {
+ if (testFunctionAttribute(def->type.firstToken, def))
+ ; // fine
+ else if (def->type.firstToken == Q_SIGNALS_TOKEN)
+ error();
+ else if (def->type.firstToken == Q_SLOTS_TOKEN)
+ error();
+ else {
+ if (!def->tag.isEmpty())
+ def->tag += ' ';
+ def->tag += def->type.name;
+ }
+ def->type = tempType;
+ tempType = parseType();
+ }
+ next(LPAREN, "Not a signal or slot declaration");
+ def->name = tempType.name;
+ scopedFunctionName = tempType.isScoped;
+
+ if (!test(RPAREN)) {
+ parseFunctionArguments(def);
+ next(RPAREN);
+ }
+
+ // support optional macros with compiler specific options
+ while (test(IDENTIFIER))
+ ;
+
+ def->isConst = test(CONST);
+
+ while (test(IDENTIFIER))
+ ;
+
+ if (inMacro) {
+ next(RPAREN);
+ prev();
+ } else {
+ if (test(THROW)) {
+ next(LPAREN);
+ until(RPAREN);
+ }
+
+ if (def->type.name == "auto" && test(ARROW))
+ def->type = parseType(); // Parse trailing return-type
+
+ if (test(SEMIC))
+ ;
+ else if ((def->inlineCode = test(LBRACE)))
+ until(RBRACE);
+ else if ((def->isAbstract = test(EQ)))
+ until(SEMIC);
+ else if (skipCxxAttributes())
+ until(SEMIC);
+ else
+ error();
+ }
+ if (scopedFunctionName) {
+ const QByteArray msg = "Function declaration " + def->name
+ + " contains extra qualification. Ignoring as signal or slot.";
+ warning(msg.constData());
+ return false;
+ }
+
+ QList<QByteArray> typeNameParts = normalizeType(def->type.name).split(' ');
+ if (typeNameParts.contains("auto")) {
+ // We expected a trailing return type but we haven't seen one
+ error("Function declared with auto as return type but missing trailing return type. "
+ "Return type deduction is not supported.");
+ }
+
+ // we don't support references as return types, it's too dangerous
+ if (def->type.referenceType == Type::Reference) {
+ QByteArray rawName = def->type.rawName;
+ def->type = Type("void");
+ def->type.rawName = rawName;
+ }
+
+ def->normalizedType = normalizeType(def->type.name);
+ return true;
+}
+
+bool Moc::testForFunctionModifiers(FunctionDef *def)
+{
+ return test(EXPLICIT) || test(INLINE) ||
+ (test(STATIC) && (def->isStatic = true)) ||
+ (test(VIRTUAL) && (def->isVirtual = true));
+}
+
+// like parseFunction, but never aborts with an error
+bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
+{
+ def->isVirtual = false;
+ def->isStatic = false;
+ //skip modifiers and attributes
+ while (testForFunctionModifiers(def)
+ || skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {}
+ bool tilde = test(TILDE);
+ def->type = parseType();
+ if (def->type.name.isEmpty())
+ return false;
+ bool scopedFunctionName = false;
+ if (test(LPAREN)) {
+ def->name = def->type.name;
+ scopedFunctionName = def->type.isScoped;
+ if (def->name == cdef->classname) {
+ def->isDestructor = tilde;
+ def->isConstructor = !tilde;
+ def->type = Type();
+ } else {
+ // missing type name? => Skip
+ return false;
+ }
+ } else {
+ // ### TODO: The condition before testForFunctionModifiers shoulnd't be necessary,
+ // but otherwise we end up with misparses
+ if (def->isSlot || def->isSignal || def->isInvokable)
+ while (testForFunctionModifiers(def)) {}
+ Type tempType = parseType();;
+ while (!tempType.name.isEmpty() && lookup() != LPAREN) {
+ if (testFunctionAttribute(def->type.firstToken, def))
+ ; // fine
+ else if (def->type.name == "Q_SIGNAL")
+ def->isSignal = true;
+ else if (def->type.name == "Q_SLOT")
+ def->isSlot = true;
+ else {
+ if (!def->tag.isEmpty())
+ def->tag += ' ';
+ def->tag += def->type.name;
+ }
+ def->type = tempType;
+ tempType = parseType();
+ }
+ if (!test(LPAREN))
+ return false;
+ def->name = tempType.name;
+ scopedFunctionName = tempType.isScoped;
+ }
+
+ // we don't support references as return types, it's too dangerous
+ if (def->type.referenceType == Type::Reference) {
+ QByteArray rawName = def->type.rawName;
+ def->type = Type("void");
+ def->type.rawName = rawName;
+ }
+
+ def->normalizedType = normalizeType(def->type.name);
+
+ if (!test(RPAREN)) {
+ parseFunctionArguments(def);
+ if (!test(RPAREN))
+ return false;
+ }
+ def->isConst = test(CONST);
+ if (scopedFunctionName
+ && (def->isSignal || def->isSlot || def->isInvokable)) {
+ const QByteArray msg = "parsemaybe: Function declaration " + def->name
+ + " contains extra qualification. Ignoring as signal or slot.";
+ warning(msg.constData());
+ return false;
+ }
+ return true;
+}
+
+inline void handleDefaultArguments(QList<FunctionDef> *functionList, FunctionDef &function)
+{
+ // support a function with a default argument by pretending there is an
+ // overload without the argument (the original function is the overload with
+ // all arguments present)
+ while (function.arguments.size() > 0 && function.arguments.constLast().isDefault) {
+ function.wasCloned = true;
+ function.arguments.removeLast();
+ *functionList += function;
+ }
+}
+
+void Moc::prependNamespaces(BaseDef &def, const QList<NamespaceDef> &namespaceList) const
+{
+ auto it = namespaceList.crbegin();
+ const auto rend = namespaceList.crend();
+ for (; it != rend; ++it) {
+ if (inNamespace(&*it))
+ def.qualified.prepend(it->classname + "::");
+ }
+}
+
+void Moc::checkListSizes(const ClassDef &def)
+{
+ if (Q_UNLIKELY(def.nonClassSignalList.size() > std::numeric_limits<int>::max()))
+ error("number of signals defined in parent class(es) exceeds "
+ "std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.propertyList.size() > std::numeric_limits<int>::max()))
+ error("number of bindable properties exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.classInfoList.size() > std::numeric_limits<int>::max()))
+ error("number of times Q_CLASSINFO macro is used exceeds "
+ "std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.enumList.size() > std::numeric_limits<int>::max()))
+ error("number of enumerations exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.superclassList.size() > std::numeric_limits<int>::max()))
+ error("number of super classes exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.constructorList.size() > std::numeric_limits<int>::max()))
+ error("number of constructor parameters exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.signalList.size() > std::numeric_limits<int>::max()))
+ error("number of signals exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.slotList.size() > std::numeric_limits<int>::max()))
+ error("number of declared slots exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.methodList.size() > std::numeric_limits<int>::max()))
+ error("number of methods exceeds std::numeric_limits<int>::max().");
+
+ if (Q_UNLIKELY(def.publicList.size() > std::numeric_limits<int>::max()))
+ error("number of public functions declared in this class exceeds "
+ "std::numeric_limits<int>::max().");
+}
+
+void Moc::parse()
+{
+ QList<NamespaceDef> namespaceList;
+ bool templateClass = false;
+ while (hasNext()) {
+ Token t = next();
+ switch (t) {
+ case NAMESPACE: {
+ qsizetype rewind = index;
+ if (test(IDENTIFIER)) {
+ QByteArray nsName = lexem();
+ QByteArrayList nested;
+ while (test(SCOPE)) {
+ /* treat (C++20's) namespace A::inline B {} as A::B
+ this is mostly to not break compilation when encountering such
+ a construct in a header; the interaction of Qt's meta-macros with
+ inline namespaces is still rather poor.
+ */
+ test(INLINE);
+ next(IDENTIFIER);
+ nested.append(nsName);
+ nsName = lexem();
+ }
+ if (test(EQ)) {
+ // namespace Foo = Bar::Baz;
+ until(SEMIC);
+ } else if (test(LPAREN)) {
+ // Ignore invalid code such as: 'namespace __identifier("x")' (QTBUG-56634)
+ until(RPAREN);
+ } else if (!test(SEMIC)) {
+ NamespaceDef def;
+ def.classname = nsName;
+ def.doGenerate = currentFilenames.size() <= 1;
+
+ next(LBRACE);
+ def.begin = index - 1;
+ until(RBRACE);
+ def.end = index;
+ index = def.begin + 1;
+
+ prependNamespaces(def, namespaceList);
+
+ for (const QByteArray &ns : nested) {
+ NamespaceDef parentNs;
+ parentNs.classname = ns;
+ parentNs.qualified = def.qualified;
+ def.qualified += ns + "::";
+ parentNs.begin = def.begin;
+ parentNs.end = def.end;
+ namespaceList += parentNs;
+ }
+
+ while (inNamespace(&def) && hasNext()) {
+ switch (next()) {
+ case NAMESPACE:
+ if (test(IDENTIFIER)) {
+ while (test(SCOPE)) {
+ test(INLINE); // ignore inline namespaces
+ next(IDENTIFIER);
+ }
+ if (test(EQ)) {
+ // namespace Foo = Bar::Baz;
+ until(SEMIC);
+ } else if (!test(SEMIC)) {
+ until(RBRACE);
+ }
+ }
+ break;
+ case Q_NAMESPACE_TOKEN:
+ def.hasQNamespace = true;
+ break;
+ case Q_NAMESPACE_EXPORT_TOKEN:
+ next(LPAREN);
+ while (test(IDENTIFIER))
+ {}
+ next(RPAREN);
+ def.hasQNamespace = true;
+ break;
+ case Q_ENUMS_TOKEN:
+ case Q_ENUM_NS_TOKEN:
+ parseEnumOrFlag(&def, false);
+ break;
+ case Q_ENUM_TOKEN:
+ error("Q_ENUM can't be used in a Q_NAMESPACE, use Q_ENUM_NS instead");
+ break;
+ case Q_FLAGS_TOKEN:
+ case Q_FLAG_NS_TOKEN:
+ parseEnumOrFlag(&def, true);
+ break;
+ case Q_FLAG_TOKEN:
+ error("Q_FLAG can't be used in a Q_NAMESPACE, use Q_FLAG_NS instead");
+ break;
+ case Q_DECLARE_FLAGS_TOKEN:
+ parseFlag(&def);
+ break;
+ case Q_CLASSINFO_TOKEN:
+ parseClassInfo(&def);
+ break;
+ case Q_MOC_INCLUDE_TOKEN:
+ // skip it, the namespace is parsed twice
+ next(LPAREN);
+ lexemUntil(RPAREN);
+ break;
+ case ENUM: {
+ EnumDef enumDef;
+ if (parseEnum(&enumDef))
+ def.enumList += enumDef;
+ } break;
+ case CLASS:
+ case STRUCT: {
+ ClassDef classdef;
+ if (!parseClassHead(&classdef))
+ continue;
+ while (inClass(&classdef) && hasNext())
+ next(); // consume all Q_XXXX macros from this class
+ } break;
+ default: break;
+ }
+ }
+ namespaceList += def;
+ index = rewind;
+ if (!def.hasQNamespace && (!def.classInfoList.isEmpty() || !def.enumDeclarations.isEmpty()))
+ error("Namespace declaration lacks Q_NAMESPACE macro.");
+ }
+ }
+ break;
+ }
+ case SEMIC:
+ case RBRACE:
+ templateClass = false;
+ break;
+ case TEMPLATE:
+ templateClass = true;
+ break;
+ case MOC_INCLUDE_BEGIN:
+ currentFilenames.push(symbol().unquotedLexem());
+ break;
+ case MOC_INCLUDE_END:
+ currentFilenames.pop();
+ break;
+ case Q_DECLARE_INTERFACE_TOKEN:
+ parseDeclareInterface();
+ break;
+ case Q_DECLARE_METATYPE_TOKEN:
+ parseDeclareMetatype();
+ break;
+ case Q_MOC_INCLUDE_TOKEN:
+ parseMocInclude();
+ break;
+ case USING:
+ if (test(NAMESPACE)) {
+ while (test(SCOPE) || test(IDENTIFIER))
+ ;
+ // Ignore invalid code such as: 'using namespace __identifier("x")' (QTBUG-63772)
+ if (test(LPAREN))
+ until(RPAREN);
+ next(SEMIC);
+ }
+ break;
+ case CLASS:
+ case STRUCT: {
+ if (currentFilenames.size() <= 1)
+ break;
+
+ ClassDef def;
+ if (!parseClassHead(&def))
+ continue;
+
+ while (inClass(&def) && hasNext()) {
+ switch (next()) {
+ case Q_OBJECT_TOKEN:
+ def.hasQObject = true;
+ break;
+ case Q_GADGET_EXPORT_TOKEN:
+ next(LPAREN);
+ while (test(IDENTIFIER))
+ {}
+ next(RPAREN);
+ Q_FALLTHROUGH();
+ case Q_GADGET_TOKEN:
+ def.hasQGadget = true;
+ break;
+ default: break;
+ }
+ }
+
+ if (!def.hasQObject && !def.hasQGadget)
+ continue;
+
+ prependNamespaces(def, namespaceList);
+
+ QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
+ classHash.insert(def.classname, def.qualified);
+ classHash.insert(def.qualified, def.qualified);
+
+ continue; }
+ default: break;
+ }
+ if ((t != CLASS && t != STRUCT)|| currentFilenames.size() > 1)
+ continue;
+ ClassDef def;
+ if (parseClassHead(&def)) {
+ prependNamespaces(def, namespaceList);
+
+ FunctionDef::Access access = FunctionDef::Private;
+ while (inClass(&def) && hasNext()) {
+ switch ((t = next())) {
+ case PRIVATE:
+ access = FunctionDef::Private;
+ if (test(Q_SIGNALS_TOKEN))
+ error("Signals cannot have access specifier");
+ break;
+ case PROTECTED:
+ access = FunctionDef::Protected;
+ if (test(Q_SIGNALS_TOKEN))
+ error("Signals cannot have access specifier");
+ break;
+ case PUBLIC:
+ access = FunctionDef::Public;
+ if (test(Q_SIGNALS_TOKEN))
+ error("Signals cannot have access specifier");
+ break;
+ case CLASS: {
+ ClassDef nestedDef;
+ if (parseClassHead(&nestedDef)) {
+ while (inClass(&nestedDef) && inClass(&def)) {
+ t = next();
+ if (t >= Q_META_TOKEN_BEGIN && t < Q_META_TOKEN_END)
+ error("Meta object features not supported for nested classes");
+ }
+ }
+ } break;
+ case Q_SIGNALS_TOKEN:
+ parseSignals(&def);
+ break;
+ case Q_SLOTS_TOKEN:
+ switch (lookup(-1)) {
+ case PUBLIC:
+ case PROTECTED:
+ case PRIVATE:
+ parseSlots(&def, access);
+ break;
+ default:
+ error("Missing access specifier for slots");
+ }
+ break;
+ case Q_OBJECT_TOKEN:
+ def.hasQObject = true;
+ if (templateClass)
+ error("Template classes not supported by Q_OBJECT");
+ if (def.classname != "Qt" && def.classname != "QObject" && def.superclassList.isEmpty())
+ error("Class contains Q_OBJECT macro but does not inherit from QObject");
+ break;
+ case Q_GADGET_EXPORT_TOKEN:
+ next(LPAREN);
+ while (test(IDENTIFIER))
+ {}
+ next(RPAREN);
+ Q_FALLTHROUGH();
+ case Q_GADGET_TOKEN:
+ def.hasQGadget = true;
+ if (templateClass)
+ error("Template classes not supported by Q_GADGET");
+ break;
+ case Q_PROPERTY_TOKEN:
+ parseProperty(&def, Named);
+ break;
+ case QT_ANONYMOUS_PROPERTY_TOKEN:
+ parseProperty(&def, Anonymous);
+ break;
+ case Q_PLUGIN_METADATA_TOKEN:
+ parsePluginData(&def);
+ break;
+ case Q_ENUMS_TOKEN:
+ case Q_ENUM_TOKEN:
+ parseEnumOrFlag(&def, false);
+ break;
+ case Q_ENUM_NS_TOKEN:
+ error("Q_ENUM_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_ENUM instead");
+ break;
+ case Q_FLAGS_TOKEN:
+ case Q_FLAG_TOKEN:
+ parseEnumOrFlag(&def, true);
+ break;
+ case Q_FLAG_NS_TOKEN:
+ error("Q_FLAG_NS can't be used in a Q_OBJECT/Q_GADGET, use Q_FLAG instead");
+ break;
+ case Q_DECLARE_FLAGS_TOKEN:
+ parseFlag(&def);
+ break;
+ case Q_CLASSINFO_TOKEN:
+ parseClassInfo(&def);
+ break;
+ case Q_MOC_INCLUDE_TOKEN:
+ parseMocInclude();
+ break;
+ case Q_INTERFACES_TOKEN:
+ parseInterfaces(&def);
+ break;
+ case Q_PRIVATE_SLOT_TOKEN:
+ parseSlotInPrivate(&def, access);
+ break;
+ case Q_PRIVATE_PROPERTY_TOKEN:
+ parsePrivateProperty(&def, Named);
+ break;
+ case QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN:
+ parsePrivateProperty(&def, Anonymous);
+ break;
+ case ENUM: {
+ EnumDef enumDef;
+ if (parseEnum(&enumDef))
+ def.enumList += enumDef;
+ } break;
+ case SEMIC:
+ case COLON:
+ break;
+ default:
+ FunctionDef funcDef;
+ funcDef.access = access;
+ qsizetype rewind = index--;
+ if (parseMaybeFunction(&def, &funcDef)) {
+ if (funcDef.isConstructor) {
+ if ((access == FunctionDef::Public) && funcDef.isInvokable) {
+ def.constructorList += funcDef;
+ handleDefaultArguments(&def.constructorList, funcDef);
+ }
+ } else if (funcDef.isDestructor) {
+ // don't care about destructors
+ } else {
+ if (access == FunctionDef::Public)
+ def.publicList += funcDef;
+ if (funcDef.isSlot) {
+ def.slotList += funcDef;
+ handleDefaultArguments(&def.slotList, funcDef);
+ if (funcDef.revision > 0)
+ ++def.revisionedMethods;
+ } else if (funcDef.isSignal) {
+ def.signalList += funcDef;
+ handleDefaultArguments(&def.signalList, funcDef);
+ if (funcDef.revision > 0)
+ ++def.revisionedMethods;
+ } else if (funcDef.isInvokable) {
+ def.methodList += funcDef;
+ handleDefaultArguments(&def.methodList, funcDef);
+ if (funcDef.revision > 0)
+ ++def.revisionedMethods;
+ }
+ }
+ } else {
+ index = rewind;
+ }
+ }
+ }
+
+ next(RBRACE);
+
+ if (!def.hasQObject && !def.hasQGadget && def.signalList.isEmpty() && def.slotList.isEmpty()
+ && def.propertyList.isEmpty() && def.enumDeclarations.isEmpty())
+ continue; // no meta object code required
+
+
+ if (!def.hasQObject && !def.hasQGadget)
+ error("Class declaration lacks Q_OBJECT macro.");
+
+ // Add meta tags to the plugin meta data:
+ if (!def.pluginData.iid.isEmpty())
+ def.pluginData.metaArgs = metaArgs;
+
+ if (def.hasQObject && !def.superclassList.isEmpty())
+ checkSuperClasses(&def);
+
+ checkProperties(&def);
+
+ checkListSizes(def);
+
+ classList += def;
+ QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets;
+ classHash.insert(def.classname, def.qualified);
+ classHash.insert(def.qualified, def.qualified);
+ }
+ }
+ for (const auto &n : std::as_const(namespaceList)) {
+ if (!n.hasQNamespace)
+ continue;
+ ClassDef def;
+ static_cast<BaseDef &>(def) = static_cast<BaseDef>(n);
+ def.qualified += def.classname;
+ def.hasQNamespace = true;
+ auto it = std::find_if(classList.begin(), classList.end(), [&def](const ClassDef &val) {
+ return def.classname == val.classname && def.qualified == val.qualified;
+ });
+
+ if (it != classList.end()) {
+ it->classInfoList += def.classInfoList;
+ Q_ASSERT(it->classInfoList.size() <= std::numeric_limits<int>::max());
+ it->enumDeclarations.insert(def.enumDeclarations);
+ it->enumList += def.enumList;
+ Q_ASSERT(it->enumList.size() <= std::numeric_limits<int>::max());
+ it->flagAliases.insert(def.flagAliases);
+ } else {
+ knownGadgets.insert(def.classname, def.qualified);
+ knownGadgets.insert(def.qualified, def.qualified);
+ if (n.doGenerate)
+ classList += def;
+ }
+ }
+}
+
+static bool any_type_contains(const QList<PropertyDef> &properties, const QByteArray &pattern)
+{
+ for (const auto &p : properties) {
+ if (p.type.contains(pattern))
+ return true;
+ }
+ return false;
+}
+
+static bool any_arg_contains(const QList<FunctionDef> &functions, const QByteArray &pattern)
+{
+ for (const auto &f : functions) {
+ for (const auto &arg : f.arguments) {
+ if (arg.normalizedType.contains(pattern))
+ return true;
+ }
+ }
+ return false;
+}
+
+static QByteArrayList make_candidates()
+{
+ QByteArrayList result;
+ result
+#define STREAM_SMART_POINTER(SMART_POINTER) << #SMART_POINTER
+ QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(STREAM_SMART_POINTER)
+#undef STREAM_SMART_POINTER
+#define STREAM_1ARG_TEMPLATE(TEMPLATENAME) << #TEMPLATENAME
+ QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(STREAM_1ARG_TEMPLATE)
+#undef STREAM_1ARG_TEMPLATE
+ ;
+ return result;
+}
+
+static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes)
+{
+ static const QByteArrayList candidates = make_candidates();
+
+ QByteArrayList required;
+ required.reserve(candidates.size());
+
+ bool needsQProperty = false;
+
+ for (const auto &candidate : candidates) {
+ const QByteArray pattern = candidate + '<';
+
+ for (const auto &c : classes) {
+ for (const auto &p : c.propertyList)
+ needsQProperty |= !p.bind.isEmpty();
+ if (any_type_contains(c.propertyList, pattern) ||
+ any_arg_contains(c.slotList, pattern) ||
+ any_arg_contains(c.signalList, pattern) ||
+ any_arg_contains(c.methodList, pattern)) {
+ required.push_back(candidate);
+ break;
+ }
+ }
+ }
+
+ if (needsQProperty)
+ required.push_back("QProperty");
+
+ return required;
+}
+
+void Moc::generate(FILE *out, FILE *jsonOutput)
+{
+ QByteArrayView fn = QByteArrayView(filename);
+
+ auto isSlash = [](char ch) { return ch == '/' || ch == '\\'; };
+ auto rit = std::find_if(fn.crbegin(), fn.crend(), isSlash);
+ if (rit != fn.crend())
+ fn = fn.last(rit - fn.crbegin());
+
+ fprintf(out, "/****************************************************************************\n"
+ "** Meta object code from reading C++ file '%s'\n**\n" , fn.constData());
+ fprintf(out, "** Created by: The Qt Meta Object Compiler version %d (Qt %s)\n**\n" , mocOutputRevision, QT_VERSION_STR);
+ fprintf(out, "** WARNING! All changes made in this file will be lost!\n"
+ "*****************************************************************************/\n\n");
+
+ // include header(s) of user class definitions at _first_ to allow
+ // for preprocessor definitions possibly affecting standard headers.
+ // see https://codereview.qt-project.org/c/qt/qtbase/+/445937
+ if (!noInclude) {
+ if (includePath.size() && !includePath.endsWith('/'))
+ includePath += '/';
+ for (QByteArray inc : std::as_const(includeFiles)) {
+ if (!inc.isEmpty() && inc.at(0) != '<' && inc.at(0) != '"') {
+ if (includePath.size() && includePath != "./")
+ inc.prepend(includePath);
+ inc = '\"' + inc + '\"';
+ }
+ fprintf(out, "#include %s\n", inc.constData());
+ }
+ }
+ if (classList.size() && classList.constFirst().classname == "Qt")
+ fprintf(out, "#include <QtCore/qobject.h>\n");
+
+ fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type
+ if (mustIncludeQPluginH)
+ fprintf(out, "#include <QtCore/qplugin.h>\n");
+
+ const auto qtContainers = requiredQtContainers(classList);
+ for (const QByteArray &qtContainer : qtContainers)
+ fprintf(out, "#include <QtCore/%s>\n", qtContainer.constData());
+
+ fprintf(out, "\n#include <QtCore/qtmochelpers.h>\n");
+
+ fprintf(out, "\n#include <memory>\n\n"); // For std::addressof
+ fprintf(out, "\n#include <QtCore/qxptype_traits.h>\n"); // is_detected
+
+ fprintf(out, "#if !defined(Q_MOC_OUTPUT_REVISION)\n"
+ "#error \"The header file '%s' doesn't include <QObject>.\"\n", fn.constData());
+ fprintf(out, "#elif Q_MOC_OUTPUT_REVISION != %d\n", mocOutputRevision);
+ fprintf(out, "#error \"This file was generated using the moc from %s."
+ " It\"\n#error \"cannot be used with the include files from"
+ " this version of Qt.\"\n#error \"(The moc has changed too"
+ " much.)\"\n", QT_VERSION_STR);
+ fprintf(out, "#endif\n\n");
+
+#if QT_VERSION <= QT_VERSION_CHECK(7, 0, 0)
+ fprintf(out, "#ifndef Q_CONSTINIT\n"
+ "#define Q_CONSTINIT\n"
+ "#endif\n\n");
+#endif
+
+ fprintf(out, "QT_WARNING_PUSH\n");
+ fprintf(out, "QT_WARNING_DISABLE_DEPRECATED\n");
+ fprintf(out, "QT_WARNING_DISABLE_GCC(\"-Wuseless-cast\")\n");
+
+ fputs("", out);
+ for (ClassDef &def : classList) {
+ Generator generator(this, &def, metaTypes, knownQObjectClasses, knownGadgets, out,
+ requireCompleteTypes);
+ generator.generateCode();
+
+ // generator.generateCode() should have already registered all strings
+ if (Q_UNLIKELY(generator.registeredStringsCount() >= std::numeric_limits<int>::max())) {
+ error("internal limit exceeded: number of parsed strings is too big.");
+ exit(EXIT_FAILURE);
+ }
+ }
+ fputs("", out);
+
+ fprintf(out, "QT_WARNING_POP\n");
+
+ if (jsonOutput) {
+ QJsonObject mocData;
+ mocData["outputRevision"_L1] = mocOutputRevision;
+ mocData["inputFile"_L1] = QLatin1StringView(fn.constData());
+
+ QJsonArray classesJsonFormatted;
+
+ for (const ClassDef &cdef: std::as_const(classList))
+ classesJsonFormatted.append(cdef.toJson());
+
+ if (!classesJsonFormatted.isEmpty())
+ mocData["classes"_L1] = classesJsonFormatted;
+
+ QJsonDocument jsonDoc(mocData);
+ fputs(jsonDoc.toJson().constData(), jsonOutput);
+ }
+}
+
+void Moc::parseSlots(ClassDef *def, FunctionDef::Access access)
+{
+ QTypeRevision defaultRevision;
+ if (test(Q_REVISION_TOKEN))
+ defaultRevision = parseRevision();
+
+ next(COLON);
+ while (inClass(def) && hasNext()) {
+ switch (next()) {
+ case PUBLIC:
+ case PROTECTED:
+ case PRIVATE:
+ case Q_SIGNALS_TOKEN:
+ case Q_SLOTS_TOKEN:
+ prev();
+ return;
+ case SEMIC:
+ continue;
+ case FRIEND:
+ until(SEMIC);
+ continue;
+ case USING:
+ error("'using' directive not supported in 'slots' section");
+ default:
+ prev();
+ }
+
+ FunctionDef funcDef;
+ funcDef.access = access;
+ if (!parseFunction(&funcDef))
+ continue;
+ if (funcDef.revision > 0) {
+ ++def->revisionedMethods;
+ } else if (defaultRevision.isValid()) {
+ funcDef.revision = defaultRevision.toEncodedVersion<int>();
+ ++def->revisionedMethods;
+ }
+ def->slotList += funcDef;
+ handleDefaultArguments(&def->slotList, funcDef);
+ }
+}
+
+void Moc::parseSignals(ClassDef *def)
+{
+ QTypeRevision defaultRevision;
+ if (test(Q_REVISION_TOKEN))
+ defaultRevision = parseRevision();
+
+ next(COLON);
+ while (inClass(def) && hasNext()) {
+ switch (next()) {
+ case PUBLIC:
+ case PROTECTED:
+ case PRIVATE:
+ case Q_SIGNALS_TOKEN:
+ case Q_SLOTS_TOKEN:
+ prev();
+ return;
+ case SEMIC:
+ continue;
+ case FRIEND:
+ until(SEMIC);
+ continue;
+ case USING:
+ error("'using' directive not supported in 'signals' section");
+ default:
+ prev();
+ }
+ FunctionDef funcDef;
+ funcDef.access = FunctionDef::Public;
+ parseFunction(&funcDef);
+ if (funcDef.isVirtual)
+ warning("Signals cannot be declared virtual");
+ if (funcDef.inlineCode)
+ error("Not a signal declaration");
+ if (funcDef.revision > 0) {
+ ++def->revisionedMethods;
+ } else if (defaultRevision.isValid()) {
+ funcDef.revision = defaultRevision.toEncodedVersion<int>();
+ ++def->revisionedMethods;
+ }
+ def->signalList += funcDef;
+ handleDefaultArguments(&def->signalList, funcDef);
+ }
+}
+
+void Moc::createPropertyDef(PropertyDef &propDef, int propertyIndex, Moc::PropertyMode mode)
+{
+ propDef.location = index;
+ propDef.relativeIndex = propertyIndex;
+
+ QByteArray type = parseType().name;
+ if (type.isEmpty())
+ error();
+ propDef.designable = propDef.scriptable = propDef.stored = "true";
+ propDef.user = "false";
+ /*
+ The Q_PROPERTY construct cannot contain any commas, since
+ commas separate macro arguments. We therefore expect users
+ to type "QMap" instead of "QMap<QString, QVariant>". For
+ coherence, we also expect the same for
+ QValueList<QVariant>, the other template class supported by
+ QVariant.
+ */
+ type = normalizeType(type);
+ if (type == "QMap")
+ type = "QMap<QString,QVariant>";
+ else if (type == "QValueList")
+ type = "QValueList<QVariant>";
+ else if (type == "LongLong")
+ type = "qlonglong";
+ else if (type == "ULongLong")
+ type = "qulonglong";
+
+ propDef.type = type;
+
+ if (mode == Moc::Named) {
+ next();
+ propDef.name = lexem();
+ }
+
+ parsePropertyAttributes(propDef);
+}
+
+void Moc::parsePropertyAttributes(PropertyDef &propDef)
+{
+ auto checkIsFunction = [&](const QByteArray &def, const char *name) {
+ if (def.endsWith(')')) {
+ QByteArray msg = "Providing a function for ";
+ msg += name;
+ msg += " in a property declaration is not be supported in Qt 6.";
+ error(msg.constData());
+ }
+ };
+
+ while (test(IDENTIFIER)) {
+ const Symbol &lsym = symbol();
+ const QByteArray l = lsym.lexem();
+ if (l[0] == 'C' && l == "CONSTANT") {
+ propDef.constant = true;
+ continue;
+ } else if (l[0] == 'F' && l == "FINAL") {
+ propDef.final = true;
+ continue;
+ } else if (l[0] == 'N' && l == "NAME") {
+ next(IDENTIFIER);
+ propDef.name = lexem();
+ continue;
+ } else if (l[0] == 'R' && l == "REQUIRED") {
+ propDef.required = true;
+ continue;
+ } else if (l[0] == 'R' && l == "REVISION" && test(LPAREN)) {
+ prev();
+ propDef.revision = parseRevision().toEncodedVersion<int>();
+ continue;
+ }
+
+ QByteArray v, v2;
+ if (test(LPAREN)) {
+ v = lexemUntil(RPAREN);
+ v = v.mid(1, v.size() - 2); // removes the '(' and ')'
+ } else if (test(INTEGER_LITERAL)) {
+ v = lexem();
+ if (l != "REVISION")
+ error(lsym);
+ } else if (test(DEFAULT)) {
+ v = lexem();
+ if (l != "READ" && l != "WRITE")
+ error(lsym);
+ } else {
+ next(IDENTIFIER);
+ v = lexem();
+ if (test(LPAREN))
+ v2 = lexemUntil(RPAREN);
+ else if (v != "true" && v != "false")
+ v2 = "()";
+ }
+ switch (l[0]) {
+ case 'M':
+ if (l == "MEMBER")
+ propDef.member = v;
+ else
+ error(lsym);
+ break;
+ case 'R':
+ if (l == "READ")
+ propDef.read = v;
+ else if (l == "RESET")
+ propDef.reset = v;
+ else if (l == "REVISION") {
+ bool ok = false;
+ const int minor = v.toInt(&ok);
+ if (!ok || !QTypeRevision::isValidSegment(minor))
+ error(lsym);
+ propDef.revision = QTypeRevision::fromMinorVersion(minor).toEncodedVersion<int>();
+ } else
+ error(lsym);
+ break;
+ case 'S':
+ if (l == "SCRIPTABLE") {
+ propDef.scriptable = v + v2;
+ checkIsFunction(propDef.scriptable, "SCRIPTABLE");
+ } else if (l == "STORED") {
+ propDef.stored = v + v2;
+ checkIsFunction(propDef.stored, "STORED");
+ } else
+ error(lsym);
+ break;
+ case 'W': if (l != "WRITE") error(lsym);
+ propDef.write = v;
+ break;
+ case 'B': if (l != "BINDABLE") error(lsym);
+ propDef.bind = v;
+ break;
+ case 'D': if (l != "DESIGNABLE") error(lsym);
+ propDef.designable = v + v2;
+ checkIsFunction(propDef.designable, "DESIGNABLE");
+ break;
+ case 'N': if (l != "NOTIFY") error(lsym);
+ propDef.notify = v;
+ break;
+ case 'U': if (l != "USER") error(lsym);
+ propDef.user = v + v2;
+ checkIsFunction(propDef.user, "USER");
+ break;
+ default:
+ error(lsym);
+ }
+ }
+ if (propDef.constant && !propDef.write.isNull()) {
+ const QByteArray msg = "Property declaration " + propDef.name
+ + " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
+ propDef.constant = false;
+ warning(msg.constData());
+ }
+ if (propDef.constant && !propDef.notify.isNull()) {
+ const QByteArray msg = "Property declaration " + propDef.name
+ + " is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
+ propDef.constant = false;
+ warning(msg.constData());
+ }
+ if (propDef.constant && !propDef.bind.isNull()) {
+ const QByteArray msg = "Property declaration " + propDef.name
+ + " is both BINDable and CONSTANT. CONSTANT will be ignored.";
+ propDef.constant = false;
+ warning(msg.constData());
+ }
+ if (propDef.read == "default" && propDef.bind.isNull()) {
+ const QByteArray msg = "Property declaration " + propDef.name
+ + " is not BINDable but default-READable. READ will be ignored.";
+ propDef.read = "";
+ warning(msg.constData());
+ }
+ if (propDef.write == "default" && propDef.bind.isNull()) {
+ const QByteArray msg = "Property declaration " + propDef.name
+ + " is not BINDable but default-WRITEable. WRITE will be ignored.";
+ propDef.write = "";
+ warning(msg.constData());
+ }
+}
+
+void Moc::parseProperty(ClassDef *def, Moc::PropertyMode mode)
+{
+ next(LPAREN);
+ PropertyDef propDef;
+ createPropertyDef(propDef, int(def->propertyList.size()), mode);
+ next(RPAREN);
+
+ def->propertyList += propDef;
+}
+
+void Moc::parsePluginData(ClassDef *def)
+{
+ next(LPAREN);
+ QByteArray metaData;
+ while (test(IDENTIFIER)) {
+ QByteArray l = lexem();
+ if (l == "IID") {
+ next(STRING_LITERAL);
+ def->pluginData.iid = unquotedLexem();
+ } else if (l == "URI") {
+ next(STRING_LITERAL);
+ def->pluginData.uri = unquotedLexem();
+ } else if (l == "FILE") {
+ next(STRING_LITERAL);
+ QByteArray metaDataFile = unquotedLexem();
+ QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top())).dir(),
+ QString::fromLocal8Bit(metaDataFile));
+ for (const IncludePath &p : std::as_const(includes)) {
+ if (fi.exists())
+ break;
+ if (p.isFrameworkPath)
+ continue;
+
+ fi.setFile(QString::fromLocal8Bit(p.path.constData()), QString::fromLocal8Bit(metaDataFile.constData()));
+ // try again, maybe there's a file later in the include paths with the same name
+ if (fi.isDir()) {
+ fi = QFileInfo();
+ continue;
+ }
+ }
+ if (!fi.exists()) {
+ const QByteArray msg = "Plugin Metadata file " + lexem()
+ + " does not exist. Declaration will be ignored";
+ error(msg.constData());
+ return;
+ }
+ QFile file(fi.canonicalFilePath());
+ if (!file.open(QFile::ReadOnly)) {
+ QByteArray msg = "Plugin Metadata file " + lexem() + " could not be opened: "
+ + file.errorString().toUtf8();
+ error(msg.constData());
+ return;
+ }
+ parsedPluginMetadataFiles.append(fi.canonicalFilePath());
+ metaData = file.readAll();
+ }
+ }
+
+ if (!metaData.isEmpty()) {
+ def->pluginData.metaData = QJsonDocument::fromJson(metaData);
+ if (!def->pluginData.metaData.isObject()) {
+ const QByteArray msg = "Plugin Metadata file " + lexem()
+ + " does not contain a valid JSON object. Declaration will be ignored";
+ warning(msg.constData());
+ def->pluginData.iid = QByteArray();
+ def->pluginData.uri = QByteArray();
+ return;
+ }
+ }
+
+ mustIncludeQPluginH = true;
+ next(RPAREN);
+}
+
+QByteArray Moc::parsePropertyAccessor()
+{
+ int nesting = 0;
+ QByteArray accessor;
+ while (1) {
+ Token t = peek();
+ if (!nesting && (t == RPAREN || t == COMMA))
+ break;
+ t = next();
+ if (t == LPAREN)
+ ++nesting;
+ if (t == RPAREN)
+ --nesting;
+ accessor += lexem();
+ }
+ return accessor;
+}
+
+void Moc::parsePrivateProperty(ClassDef *def, Moc::PropertyMode mode)
+{
+ next(LPAREN);
+ PropertyDef propDef;
+ propDef.inPrivateClass = parsePropertyAccessor();
+
+ next(COMMA);
+
+ createPropertyDef(propDef, int(def->propertyList.size()), mode);
+
+ def->propertyList += propDef;
+}
+
+void Moc::parseEnumOrFlag(BaseDef *def, bool isFlag)
+{
+ next(LPAREN);
+ QByteArray identifier;
+ while (test(IDENTIFIER)) {
+ identifier = lexem();
+ while (test(SCOPE) && test(IDENTIFIER)) {
+ identifier += "::";
+ identifier += lexem();
+ }
+ def->enumDeclarations[identifier] = isFlag;
+ }
+ next(RPAREN);
+}
+
+void Moc::parseFlag(BaseDef *def)
+{
+ next(LPAREN);
+ QByteArray flagName, enumName;
+ while (test(IDENTIFIER)) {
+ flagName = lexem();
+ while (test(SCOPE) && test(IDENTIFIER)) {
+ flagName += "::";
+ flagName += lexem();
+ }
+ }
+ next(COMMA);
+ while (test(IDENTIFIER)) {
+ enumName = lexem();
+ while (test(SCOPE) && test(IDENTIFIER)) {
+ enumName += "::";
+ enumName += lexem();
+ }
+ }
+
+ def->flagAliases.insert(enumName, flagName);
+ next(RPAREN);
+}
+
+Moc::EncounteredQmlMacro Moc::parseClassInfo(BaseDef *def)
+{
+ bool encounteredQmlMacro = false;
+ next(LPAREN);
+ ClassInfoDef infoDef;
+ next(STRING_LITERAL);
+ infoDef.name = symbol().unquotedLexem();
+ if (infoDef.name.startsWith("QML."))
+ encounteredQmlMacro = true;
+ next(COMMA);
+ if (test(STRING_LITERAL)) {
+ infoDef.value = symbol().unquotedLexem();
+ } else if (test(Q_REVISION_TOKEN)) {
+ infoDef.value = QByteArray::number(parseRevision().toEncodedVersion<quint16>());
+ } else {
+ // support Q_CLASSINFO("help", QT_TR_NOOP("blah"))
+ next(IDENTIFIER);
+ next(LPAREN);
+ next(STRING_LITERAL);
+ infoDef.value = symbol().unquotedLexem();
+ next(RPAREN);
+ }
+ next(RPAREN);
+ def->classInfoList += infoDef;
+ return encounteredQmlMacro ? EncounteredQmlMacro::Yes : EncounteredQmlMacro::No;
+}
+
+void Moc::parseClassInfo(ClassDef *def)
+{
+ if (parseClassInfo(static_cast<BaseDef *>(def)) == EncounteredQmlMacro::Yes)
+ def->requireCompleteMethodTypes = true;
+}
+
+void Moc::parseInterfaces(ClassDef *def)
+{
+ next(LPAREN);
+ while (test(IDENTIFIER)) {
+ QList<ClassDef::Interface> iface;
+ iface += ClassDef::Interface(lexem());
+ while (test(SCOPE)) {
+ iface.last().className += lexem();
+ next(IDENTIFIER);
+ iface.last().className += lexem();
+ }
+ while (test(COLON)) {
+ next(IDENTIFIER);
+ iface += ClassDef::Interface(lexem());
+ while (test(SCOPE)) {
+ iface.last().className += lexem();
+ next(IDENTIFIER);
+ iface.last().className += lexem();
+ }
+ }
+ // resolve from classnames to interface ids
+ for (qsizetype i = 0; i < iface.size(); ++i) {
+ const QByteArray iid = interface2IdMap.value(iface.at(i).className);
+ if (iid.isEmpty())
+ error("Undefined interface");
+
+ iface[i].interfaceId = iid;
+ }
+ def->interfaceList += iface;
+ }
+ next(RPAREN);
+}
+
+void Moc::parseDeclareInterface()
+{
+ next(LPAREN);
+ QByteArray interface;
+ next(IDENTIFIER);
+ interface += lexem();
+ while (test(SCOPE)) {
+ interface += lexem();
+ next(IDENTIFIER);
+ interface += lexem();
+ }
+ next(COMMA);
+ QByteArray iid;
+ if (test(STRING_LITERAL)) {
+ iid = lexem();
+ } else {
+ next(IDENTIFIER);
+ iid = lexem();
+ }
+ interface2IdMap.insert(interface, iid);
+ next(RPAREN);
+}
+
+void Moc::parseDeclareMetatype()
+{
+ next(LPAREN);
+ QByteArray typeName = lexemUntil(RPAREN);
+ typeName.remove(0, 1);
+ typeName.chop(1);
+ metaTypes.append(typeName);
+}
+
+void Moc::parseMocInclude()
+{
+ next(LPAREN);
+ QByteArray include = lexemUntil(RPAREN);
+ // remove parentheses
+ include.remove(0, 1);
+ include.chop(1);
+ includeFiles.append(include);
+}
+
+void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access)
+{
+ next(LPAREN);
+ FunctionDef funcDef;
+ next(IDENTIFIER);
+ funcDef.inPrivateClass = lexem();
+ // also allow void functions
+ if (test(LPAREN)) {
+ next(RPAREN);
+ funcDef.inPrivateClass += "()";
+ }
+ next(COMMA);
+ funcDef.access = access;
+ parseFunction(&funcDef, true);
+ def->slotList += funcDef;
+ handleDefaultArguments(&def->slotList, funcDef);
+ if (funcDef.revision > 0)
+ ++def->revisionedMethods;
+
+}
+
+QByteArray Moc::lexemUntil(Token target)
+{
+ qsizetype from = index;
+ until(target);
+ QByteArray s;
+ while (from <= index) {
+ QByteArray n = symbols.at(from++-1).lexem();
+ if (s.size() && n.size()) {
+ char prev = s.at(s.size()-1);
+ char next = n.at(0);
+ if ((is_ident_char(prev) && is_ident_char(next))
+ || (prev == '<' && next == ':')
+ || (prev == '>' && next == '>'))
+ s += ' ';
+ }
+ s += n;
+ }
+ return s;
+}
+
+bool Moc::until(Token target) {
+ int braceCount = 0;
+ int brackCount = 0;
+ int parenCount = 0;
+ int angleCount = 0;
+ if (index) {
+ switch(symbols.at(index-1).token) {
+ case LBRACE: ++braceCount; break;
+ case LBRACK: ++brackCount; break;
+ case LPAREN: ++parenCount; break;
+ case LANGLE: ++angleCount; break;
+ default: break;
+ }
+ }
+
+ //when searching commas within the default argument, we should take care of template depth (anglecount)
+ // unfortunately, we do not have enough semantic information to know if '<' is the operator< or
+ // the beginning of a template type. so we just use heuristics.
+ qsizetype possible = -1;
+
+ while (index < symbols.size()) {
+ Token t = symbols.at(index++).token;
+ switch (t) {
+ case LBRACE: ++braceCount; break;
+ case RBRACE: --braceCount; break;
+ case LBRACK: ++brackCount; break;
+ case RBRACK: --brackCount; break;
+ case LPAREN: ++parenCount; break;
+ case RPAREN: --parenCount; break;
+ case LANGLE:
+ if (parenCount == 0 && braceCount == 0)
+ ++angleCount;
+ break;
+ case RANGLE:
+ if (parenCount == 0 && braceCount == 0)
+ --angleCount;
+ break;
+ case GTGT:
+ if (parenCount == 0 && braceCount == 0) {
+ angleCount -= 2;
+ t = RANGLE;
+ }
+ break;
+ default: break;
+ }
+ if (t == target
+ && braceCount <= 0
+ && brackCount <= 0
+ && parenCount <= 0
+ && (target != RANGLE || angleCount <= 0)) {
+ if (target != COMMA || angleCount <= 0)
+ return true;
+ possible = index;
+ }
+
+ if (target == COMMA && t == EQ && possible != -1) {
+ index = possible;
+ return true;
+ }
+
+ if (braceCount < 0 || brackCount < 0 || parenCount < 0
+ || (target == RANGLE && angleCount < 0)) {
+ --index;
+ break;
+ }
+
+ if (braceCount <= 0 && t == SEMIC) {
+ // Abort on semicolon. Allow recovering bad template parsing (QTBUG-31218)
+ break;
+ }
+ }
+
+ if (target == COMMA && angleCount != 0 && possible != -1) {
+ index = possible;
+ return true;
+ }
+
+ return false;
+}
+
+void Moc::checkSuperClasses(ClassDef *def)
+{
+ Q_ASSERT(!def->superclassList.isEmpty());
+ const QByteArray &firstSuperclass = def->superclassList.at(0).classname;
+
+ if (!knownQObjectClasses.contains(firstSuperclass)) {
+ // enable once we /require/ include paths
+#if 0
+ const QByteArray msg
+ = "Class "
+ + def->className
+ + " contains the Q_OBJECT macro and inherits from "
+ + def->superclassList.value(0)
+ + " but that is not a known QObject subclass. You may get compilation errors.";
+ warning(msg.constData());
+#endif
+ return;
+ }
+
+ auto isRegisteredInterface = [&def](QByteArrayView super) {
+ auto matchesSuperClass = [&super](const auto &ifaces) {
+ return !ifaces.isEmpty() && ifaces.first().className == super;
+ };
+ return std::any_of(def->interfaceList.cbegin(), def->interfaceList.cend(), matchesSuperClass);
+ };
+
+ const auto end = def->superclassList.cend();
+ auto it = def->superclassList.cbegin() + 1;
+ for (; it != end; ++it) {
+ const QByteArray &superClass = it->classname;
+ if (knownQObjectClasses.contains(superClass)) {
+ const QByteArray msg
+ = "Class "
+ + def->classname
+ + " inherits from two QObject subclasses "
+ + firstSuperclass
+ + " and "
+ + superClass
+ + ". This is not supported!";
+ warning(msg.constData());
+ }
+
+ if (interface2IdMap.contains(superClass)) {
+ if (!isRegisteredInterface(superClass)) {
+ const QByteArray msg
+ = "Class "
+ + def->classname
+ + " implements the interface "
+ + superClass
+ + " but does not list it in Q_INTERFACES. qobject_cast to "
+ + superClass
+ + " will not work!";
+ warning(msg.constData());
+ }
+ }
+ }
+}
+
+void Moc::checkProperties(ClassDef *cdef)
+{
+ //
+ // specify get function, for compatibility we accept functions
+ // returning pointers, or const char * for QByteArray.
+ //
+ QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.size());
+ auto hasNoAttributes = [&](const PropertyDef &p) {
+ if (definedProperties.hasSeen(p.name)) {
+ QByteArray msg = "The property '" + p.name + "' is defined multiple times in class " + cdef->classname + ".";
+ warning(msg.constData());
+ }
+
+ if (p.read.isEmpty() && p.member.isEmpty() && p.bind.isEmpty()) {
+ QByteArray msg = "Property declaration " + p.name + " has neither an associated QProperty<> member"
+ ", nor a READ accessor function nor an associated MEMBER variable. The property will be invalid.";
+ const auto &sym = p.location >= 0 ? symbolAt(p.location) : Symbol();
+ warning(sym, msg.constData());
+ if (p.write.isEmpty())
+ return true;
+ }
+ return false;
+ };
+ cdef->propertyList.removeIf(hasNoAttributes);
+
+ for (PropertyDef &p : cdef->propertyList) {
+ for (const FunctionDef &f : std::as_const(cdef->publicList)) {
+ if (f.name != p.read)
+ continue;
+ if (!f.isConst) // get functions must be const
+ continue;
+ if (f.arguments.size()) // and must not take any arguments
+ continue;
+ PropertyDef::Specification spec = PropertyDef::ValueSpec;
+ QByteArray tmp = f.normalizedType;
+ if (p.type == "QByteArray" && tmp == "const char *")
+ tmp = "QByteArray";
+ if (tmp.left(6) == "const ")
+ tmp = tmp.mid(6);
+ if (p.type != tmp && tmp.endsWith('*')) {
+ tmp.chop(1);
+ spec = PropertyDef::PointerSpec;
+ } else if (f.type.name.endsWith('&')) { // raw type, not normalized type
+ spec = PropertyDef::ReferenceSpec;
+ }
+ if (p.type != tmp)
+ continue;
+ p.gspec = spec;
+ break;
+ }
+ if (!p.notify.isEmpty()) {
+ int notifyId = -1;
+ for (int j = 0; j < int(cdef->signalList.size()); ++j) {
+ const FunctionDef &f = cdef->signalList.at(j);
+ if (f.name != p.notify) {
+ continue;
+ } else {
+ notifyId = j /* Signal indexes start from 0 */;
+ break;
+ }
+ }
+ p.notifyId = notifyId;
+ if (notifyId == -1) {
+ const int index = int(cdef->nonClassSignalList.indexOf(p.notify));
+ if (index == -1) {
+ cdef->nonClassSignalList << p.notify;
+ p.notifyId = int(-1 - cdef->nonClassSignalList.size());
+ } else {
+ p.notifyId = int(-2 - index);
+ }
+ }
+ }
+ }
+}
+#endif // -- QtScxml
+
+QJsonObject ClassDef::toJson() const
+{
+ QJsonObject cls;
+ cls["className"_L1] = QString::fromUtf8(classname.constData());
+ cls["qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData());
+
+ QJsonArray classInfos;
+ for (const auto &info: std::as_const(classInfoList)) {
+ QJsonObject infoJson;
+ infoJson["name"_L1] = QString::fromUtf8(info.name);
+ infoJson["value"_L1] = QString::fromUtf8(info.value);
+ classInfos.append(infoJson);
+ }
+
+ if (classInfos.size())
+ cls["classInfos"_L1] = classInfos;
+
+ const auto appendFunctions = [&cls](const QString &type, const QList<FunctionDef> &funcs) {
+ QJsonArray jsonFuncs;
+
+ for (const FunctionDef &fdef: funcs)
+ jsonFuncs.append(fdef.toJson());
+
+ if (!jsonFuncs.isEmpty())
+ cls[type] = jsonFuncs;
+ };
+
+ appendFunctions("signals"_L1, signalList);
+ appendFunctions("slots"_L1, slotList);
+ appendFunctions("constructors"_L1, constructorList);
+ appendFunctions("methods"_L1, methodList);
+
+ QJsonArray props;
+
+ for (const PropertyDef &propDef: std::as_const(propertyList))
+ props.append(propDef.toJson());
+
+ if (!props.isEmpty())
+ cls["properties"_L1] = props;
+
+ if (hasQObject)
+ cls["object"_L1] = true;
+ if (hasQGadget)
+ cls["gadget"_L1] = true;
+ if (hasQNamespace)
+ cls["namespace"_L1] = true;
+
+ QJsonArray superClasses;
+
+ for (const auto &super: std::as_const(superclassList)) {
+ QJsonObject superCls;
+ superCls["name"_L1] = QString::fromUtf8(super.classname);
+ if (super.classname != super.qualified)
+ superCls["fullyQualifiedName"_L1] = QString::fromUtf8(super.qualified);
+ FunctionDef::accessToJson(&superCls, super.access);
+ superClasses.append(superCls);
+ }
+
+ if (!superClasses.isEmpty())
+ cls["superClasses"_L1] = superClasses;
+
+ QJsonArray enums;
+ for (const EnumDef &enumDef: std::as_const(enumList))
+ enums.append(enumDef.toJson(*this));
+ if (!enums.isEmpty())
+ cls["enums"_L1] = enums;
+
+ QJsonArray ifaces;
+ for (const QList<Interface> &ifaceList : interfaceList) {
+ QJsonArray jsonList;
+ for (const Interface &iface: ifaceList) {
+ QJsonObject ifaceJson;
+ ifaceJson["id"_L1] = QString::fromUtf8(iface.interfaceId);
+ ifaceJson["className"_L1] = QString::fromUtf8(iface.className);
+ jsonList.append(ifaceJson);
+ }
+ ifaces.append(jsonList);
+ }
+ if (!ifaces.isEmpty())
+ cls["interfaces"_L1] = ifaces;
+
+ return cls;
+}
+
+QJsonObject FunctionDef::toJson() const
+{
+ QJsonObject fdef;
+ fdef["name"_L1] = QString::fromUtf8(name);
+ if (!tag.isEmpty())
+ fdef["tag"_L1] = QString::fromUtf8(tag);
+ fdef["returnType"_L1] = QString::fromUtf8(normalizedType);
+
+ QJsonArray args;
+ for (const ArgumentDef &arg: arguments)
+ args.append(arg.toJson());
+
+ if (!args.isEmpty())
+ fdef["arguments"_L1] = args;
+
+ accessToJson(&fdef, access);
+
+ if (revision > 0)
+ fdef["revision"_L1] = revision;
+
+ if (wasCloned)
+ fdef["isCloned"_L1] = true;
+
+ return fdef;
+}
+
+void FunctionDef::accessToJson(QJsonObject *obj, FunctionDef::Access acs)
+{
+ switch (acs) {
+ case Private: (*obj)["access"_L1] = "private"_L1; break;
+ case Public: (*obj)["access"_L1] = "public"_L1; break;
+ case Protected: (*obj)["access"_L1] = "protected"_L1; break;
+ }
+}
+
+QJsonObject ArgumentDef::toJson() const
+{
+ QJsonObject arg;
+ arg["type"_L1] = QString::fromUtf8(normalizedType);
+ if (!name.isEmpty())
+ arg["name"_L1] = QString::fromUtf8(name);
+ return arg;
+}
+
+QJsonObject PropertyDef::toJson() const
+{
+ QJsonObject prop;
+ prop["name"_L1] = QString::fromUtf8(name);
+ prop["type"_L1] = QString::fromUtf8(type);
+
+ const auto jsonify = [&prop](const char *str, const QByteArray &member) {
+ if (!member.isEmpty())
+ prop[QLatin1StringView(str)] = QString::fromUtf8(member);
+ };
+
+ jsonify("member", member);
+ jsonify("read", read);
+ jsonify("write", write);
+ jsonify("bindable", bind);
+ jsonify("reset", reset);
+ jsonify("notify", notify);
+ jsonify("privateClass", inPrivateClass);
+
+ const auto jsonifyBoolOrString = [&prop](const char *str, const QByteArray &boolOrString) {
+ QJsonValue value;
+ if (boolOrString == "true")
+ value = true;
+ else if (boolOrString == "false")
+ value = false;
+ else
+ value = QString::fromUtf8(boolOrString); // function name to query at run-time
+ prop[QLatin1StringView(str)] = value;
+ };
+
+ jsonifyBoolOrString("designable", designable);
+ jsonifyBoolOrString("scriptable", scriptable);
+ jsonifyBoolOrString("stored", stored);
+ jsonifyBoolOrString("user", user);
+
+ prop["constant"_L1] = constant;
+ prop["final"_L1] = final;
+ prop["required"_L1] = required;
+ prop["index"_L1] = relativeIndex;
+ if (revision > 0)
+ prop["revision"_L1] = revision;
+
+ return prop;
+}
+
+QJsonObject EnumDef::toJson(const ClassDef &cdef) const
+{
+ QJsonObject def;
+ def["name"_L1] = QString::fromUtf8(name);
+ if (!enumName.isEmpty())
+ def["alias"_L1] = QString::fromUtf8(enumName);
+ if (!type.isEmpty())
+ def["type"_L1] = QString::fromUtf8(type);
+ def["isFlag"_L1] = cdef.enumDeclarations.value(name);
+ def["isClass"_L1] = isEnumClass;
+
+ QJsonArray valueArr;
+ for (const QByteArray &value: values)
+ valueArr.append(QString::fromUtf8(value));
+ if (!valueArr.isEmpty())
+ def["values"_L1] = valueArr;
+
+ return def;
+}
+
+QByteArray EnumDef::qualifiedType(const ClassDef *cdef) const
+{
+ if (name == cdef->classname) {
+ // The name of the enclosing namespace is the same as the enum class name
+ if (cdef->qualified.contains("::")) {
+ // QTBUG-112996, fully qualify by using cdef->qualified to disambiguate enum
+ // class name and enclosing namespace, e.g.:
+ // namespace A { namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) } }
+ return cdef->qualified % "::" % name;
+ } else {
+ // Just "B"; otherwise the compiler complains about the type "B::B" inside
+ // "B::staticMetaObject" in the generated code; e.g.:
+ // namespace B { Q_NAMESPACE; enum class B { }; Q_ENUM_NS(B) }
+ return name;
+ }
+ }
+ return cdef->classname % "::" % name;
+}
+
+QT_END_NAMESPACE
diff --git a/tools/qscxmlc/moc.h b/tools/qscxmlc/moc.h
index 56aedad..19aefb9 100644
--- a/tools/qscxmlc/moc.h
+++ b/tools/qscxmlc/moc.h
@@ -1,39 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef MOC_H
#define MOC_H
+// -- QtScxml
#include <QtCore/qmap.h>
#include <QtCore/qpair.h>
#include <QtCore/qjsondocument.h>
#include <QtCore/qjsonarray.h>
-#include <ctype.h>
+// -- QtScxml
+
+#include <private/qtools_p.h>
QT_BEGIN_NAMESPACE
@@ -43,26 +21,35 @@ struct Type
{
enum ReferenceType { NoReference, Reference, RValueReference, Pointer };
- inline Type() : isVolatile(false), isScoped(false), /*firstToken(NOTOKEN), */referenceType(NoReference) {}
+ inline Type() : isVolatile(false), isScoped(false), /* firstToken(NOTOKEN) -- QtScxml ,*/ referenceType(NoReference) {}
inline explicit Type(const QByteArray &_name)
- : name(_name), rawName(name), isVolatile(false), isScoped(false), /*firstToken(NOTOKEN),*/ referenceType(NoReference) {}
+ : name(_name), rawName(name), isVolatile(false), isScoped(false), /* firstToken(NOTOKEN) -- QtScxml ,*/ referenceType(NoReference) {}
QByteArray name;
//When used as a return type, the type name may be modified to remove the references.
// rawName is the type as found in the function signature
QByteArray rawName;
uint isVolatile : 1;
uint isScoped : 1;
-// Token firstToken;
+#if 0 // -- QtScxml
+ Token firstToken;
+#endif // -- QtScxml
ReferenceType referenceType;
};
+Q_DECLARE_TYPEINFO(Type, Q_RELOCATABLE_TYPE);
+struct ClassDef;
struct EnumDef
{
QByteArray name;
+ QByteArray enumName;
+ QByteArray type;
QList<QByteArray> values;
bool isEnumClass; // c++11 enum class
EnumDef() : isEnumClass(false) {}
+ QJsonObject toJson(const ClassDef &cdef) const;
+ QByteArray qualifiedType(const ClassDef *cdef) const;
};
+Q_DECLARE_TYPEINFO(EnumDef, Q_RELOCATABLE_TYPE);
struct ArgumentDef
{
@@ -71,125 +58,260 @@ struct ArgumentDef
QByteArray rightType, normalizedType, name;
QByteArray typeNameForCast; // type name to be used in cast from void * in metacall
bool isDefault;
+
+ QJsonObject toJson() const;
};
+Q_DECLARE_TYPEINFO(ArgumentDef, Q_RELOCATABLE_TYPE);
struct FunctionDef
{
- FunctionDef(): access(Private), isConst(false), isVirtual(false), isStatic(false),
- inlineCode(false), wasCloned(false), isCompat(false), isInvokable(false),
- isScriptable(false), isSlot(false), isSignal(false), isPrivateSignal(false),
- isConstructor(false), isDestructor(false), isAbstract(false), revision(0), implementation(0) {}
Type type;
+ QList<ArgumentDef> arguments;
QByteArray normalizedType;
QByteArray tag;
QByteArray name;
- QByteArray mangledName;
-
- QList<ArgumentDef> arguments;
+ QByteArray inPrivateClass;
enum Access { Private, Protected, Public };
- Access access;
- bool isConst;
- bool isVirtual;
- bool isStatic;
- bool inlineCode;
- bool wasCloned;
+ Access access = Private;
+ int revision = 0;
- QByteArray inPrivateClass;
- bool isCompat;
- bool isInvokable;
- bool isScriptable;
- bool isSlot;
- bool isSignal;
- bool isPrivateSignal;
- bool isConstructor;
- bool isDestructor;
- bool isAbstract;
-
- int revision;
-
- const char *implementation;
+ bool isConst = false;
+ bool isVirtual = false;
+ bool isStatic = false;
+ bool inlineCode = false;
+ bool wasCloned = false;
+
+#if 0 // -- QtScxml
+ bool returnTypeIsVolatile = false;
+#endif // -- QtScxml
+ bool isCompat = false;
+ bool isInvokable = false;
+ bool isScriptable = false;
+ bool isSlot = false;
+ bool isSignal = false;
+ bool isPrivateSignal = false;
+ bool isConstructor = false;
+ bool isDestructor = false;
+ bool isAbstract = false;
+ bool isRawSlot = false;
+
+ QJsonObject toJson() const;
+ static void accessToJson(QJsonObject *obj, Access acs);
+
+// -- QtScxml
+ QByteArray mangledName;
+ const char *implementation = nullptr;
+// -- QtScxml
};
+Q_DECLARE_TYPEINFO(FunctionDef, Q_RELOCATABLE_TYPE);
struct PropertyDef
{
- PropertyDef():notifyId(-1), constant(false), final(false), gspec(ValueSpec), revision(0){}
- QByteArray name, mangledName, type, member, read, write, reset, designable, scriptable,
- editable, stored, user, notify, inPrivateClass;
- int notifyId;
- bool constant;
- bool final;
- enum Specification { ValueSpec, ReferenceSpec, PointerSpec };
- Specification gspec;
bool stdCppSet() const {
+ if (name.isEmpty())
+ return false;
QByteArray s("set");
- s += toupper(name[0]);
+ s += QtMiscUtils::toAsciiUpper(name[0]);
s += name.mid(1);
return (s == write);
}
- int revision;
+
+ QByteArray name, type, member, read, write, bind, reset, designable, scriptable, stored, user, notify, inPrivateClass;
+ int notifyId = -1; // -1 means no notifyId, >= 0 means signal defined in this class, < -1 means signal not defined in this class
+ enum Specification { ValueSpec, ReferenceSpec, PointerSpec };
+ Specification gspec = ValueSpec;
+ int revision = 0;
+ bool constant = false;
+ bool final = false;
+ bool required = false;
+ int relativeIndex = -1; // property index in current metaobject
+
+ qsizetype location = -1; // token index, used for error reporting
+
+ QJsonObject toJson() const;
+
+// -- QtScxml
+ QByteArray mangledName;
+// -- QtScxml
};
+Q_DECLARE_TYPEINFO(PropertyDef, Q_RELOCATABLE_TYPE);
+struct PrivateQPropertyDef
+{
+ Type type;
+ QByteArray name;
+ QByteArray setter;
+ QByteArray accessor;
+ QByteArray storage;
+};
+Q_DECLARE_TYPEINFO(PrivateQPropertyDef, Q_RELOCATABLE_TYPE);
struct ClassInfoDef
{
QByteArray name;
QByteArray value;
};
+Q_DECLARE_TYPEINFO(ClassInfoDef, Q_RELOCATABLE_TYPE);
+
+struct BaseDef {
+ QByteArray classname;
+ QByteArray qualified;
+ QList<ClassInfoDef> classInfoList;
+ QMap<QByteArray, bool> enumDeclarations;
+ QList<EnumDef> enumList;
+ QMap<QByteArray, QByteArray> flagAliases;
+ qsizetype begin = 0;
+ qsizetype end = 0;
+};
-struct ClassDef {
- ClassDef():
- hasQObject(false), hasQGadget(false), notifyableProperties(0)
- , revisionedMethods(0), revisionedProperties(0), begin(0), end(0){}
+struct SuperClass {
QByteArray classname;
QByteArray qualified;
- QList<QPair<QByteArray, FunctionDef::Access> > superclassList;
+ FunctionDef::Access access;
+};
+Q_DECLARE_TYPEINFO(SuperClass, Q_RELOCATABLE_TYPE);
+
+struct ClassDef : BaseDef {
+ QList<SuperClass> superclassList;
struct Interface
{
+ Interface() { } // for QList, don't use
inline explicit Interface(const QByteArray &_className)
: className(_className) {}
QByteArray className;
QByteArray interfaceId;
};
- QList<QList<Interface> >interfaceList;
-
- bool hasQObject;
- bool hasQGadget;
+ QList<QList<Interface>> interfaceList;
struct PluginData {
QByteArray iid;
+ QByteArray uri;
QMap<QString, QJsonArray> metaArgs;
QJsonDocument metaData;
} pluginData;
QList<FunctionDef> constructorList;
QList<FunctionDef> signalList, slotList, methodList, publicList;
- int notifyableProperties;
+ QList<QByteArray> nonClassSignalList;
QList<PropertyDef> propertyList;
- QList<ClassInfoDef> classInfoList;
- QMap<QByteArray, bool> enumDeclarations;
- QList<EnumDef> enumList;
- QMap<QByteArray, QByteArray> flagAliases;
- int revisionedMethods;
- int revisionedProperties;
+ int revisionedMethods = 0;
+
+ bool hasQObject = false;
+ bool hasQGadget = false;
+ bool hasQNamespace = false;
+ bool requireCompleteMethodTypes = false;
- int begin;
- int end;
+ QJsonObject toJson() const;
};
+Q_DECLARE_TYPEINFO(ClassDef, Q_RELOCATABLE_TYPE);
+Q_DECLARE_TYPEINFO(ClassDef::Interface, Q_RELOCATABLE_TYPE);
-struct NamespaceDef {
- QByteArray name;
- int begin;
- int end;
+struct NamespaceDef : BaseDef {
+ bool hasQNamespace = false;
+ bool doGenerate = false;
+};
+Q_DECLARE_TYPEINFO(NamespaceDef, Q_RELOCATABLE_TYPE);
+
+#if 0 // -- QtScxml
+class Moc : public Parser
+{
+public:
+ enum PropertyMode { Named, Anonymous };
+
+ Moc()
+ : noInclude(false), mustIncludeQPluginH(false), requireCompleteTypes(false)
+ {}
+
+ QByteArray filename;
+
+ bool noInclude;
+ bool mustIncludeQPluginH;
+ bool requireCompleteTypes;
+ QByteArray includePath;
+ QList<QByteArray> includeFiles;
+ QList<ClassDef> classList;
+ QMap<QByteArray, QByteArray> interface2IdMap;
+ QList<QByteArray> metaTypes;
+ // map from class name to fully qualified name
+ QHash<QByteArray, QByteArray> knownQObjectClasses;
+ QHash<QByteArray, QByteArray> knownGadgets;
+ QMap<QString, QJsonArray> metaArgs;
+ QList<QString> parsedPluginMetadataFiles;
+
+ void parse();
+ void generate(FILE *out, FILE *jsonOutput);
+
+ bool parseClassHead(ClassDef *def);
+ inline bool inClass(const ClassDef *def) const {
+ return index > def->begin && index < def->end - 1;
+ }
+
+ inline bool inNamespace(const NamespaceDef *def) const {
+ return index > def->begin && index < def->end - 1;
+ }
+
+ const QByteArray &toFullyQualified(const QByteArray &name) const noexcept;
+
+ void prependNamespaces(BaseDef &def, const QList<NamespaceDef> &namespaceList) const;
+
+ Type parseType();
+
+ bool parseEnum(EnumDef *def);
+
+ bool parseFunction(FunctionDef *def, bool inMacro = false);
+ bool parseMaybeFunction(const ClassDef *cdef, FunctionDef *def);
+
+ void parseSlots(ClassDef *def, FunctionDef::Access access);
+ void parseSignals(ClassDef *def);
+ void parseProperty(ClassDef *def, PropertyMode mode);
+ void parsePluginData(ClassDef *def);
+
+ void createPropertyDef(PropertyDef &def, int propertyIndex, PropertyMode mode);
+
+ void parsePropertyAttributes(PropertyDef &propDef);
+ void parseEnumOrFlag(BaseDef *def, bool isFlag);
+ void parseFlag(BaseDef *def);
+ enum class EncounteredQmlMacro {Yes, No};
+ EncounteredQmlMacro parseClassInfo(BaseDef *def);
+ void parseClassInfo(ClassDef *def);
+ void parseInterfaces(ClassDef *def);
+ void parseDeclareInterface();
+ void parseDeclareMetatype();
+ void parseMocInclude();
+ void parseSlotInPrivate(ClassDef *def, FunctionDef::Access access);
+ QByteArray parsePropertyAccessor();
+ void parsePrivateProperty(ClassDef *def, PropertyMode mode);
+
+ void parseFunctionArguments(FunctionDef *def);
+
+ QByteArray lexemUntil(Token);
+ bool until(Token);
+
+ // test for Q_INVOCABLE, Q_SCRIPTABLE, etc. and set the flags
+ // in FunctionDef accordingly
+ bool testFunctionAttribute(FunctionDef *def);
+ bool testFunctionAttribute(Token tok, FunctionDef *def);
+ bool testFunctionRevision(FunctionDef *def);
+ QTypeRevision parseRevision();
+
+ bool skipCxxAttributes();
+
+ void checkSuperClasses(ClassDef *def);
+ void checkProperties(ClassDef* cdef);
+ bool testForFunctionModifiers(FunctionDef *def);
+
+ void checkListSizes(const ClassDef &def);
};
+#endif // -- QtScxml
inline QByteArray noRef(const QByteArray &type)
{
if (type.endsWith('&')) {
if (type.endsWith("&&"))
- return type.left(type.length()-2);
- return type.left(type.length()-1);
+ return type.left(type.size()-2);
+ return type.left(type.size()-1);
}
return type;
}
diff --git a/tools/qscxmlc/moc_patches/generator.cpp.patch b/tools/qscxmlc/moc_patches/generator.cpp.patch
new file mode 100644
index 0000000..26906d8
--- /dev/null
+++ b/tools/qscxmlc/moc_patches/generator.cpp.patch
@@ -0,0 +1,286 @@
+--- .upstream/generator.cpp 2024-02-01 11:08:00.055494626 +0100
++++ generator.cpp 2024-02-05 14:18:32.229391845 +0100
+@@ -4,7 +4,9 @@
+ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+ #include "generator.h"
++#if 0 // -- QtScxml
+ #include "cbordevice.h"
++#endif // -- QtScxml
+ #include "outputrevision.h"
+ #include "utils.h"
+ #include <QtCore/qmetatype.h>
+@@ -25,6 +27,29 @@
+
+ using namespace QtMiscUtils;
+
++// -- QtScxml
++void fprintf(QIODevice &out, const char *fmt, ...)
++{
++ va_list argp;
++ va_start(argp, fmt);
++ const int bufSize = 4096;
++ char buf[bufSize];
++ vsnprintf(buf, bufSize, fmt, argp);
++ va_end(argp);
++ out.write(buf);
++}
++
++void fputc(char c, QIODevice &out)
++{
++ out.write(&c, 1);
++}
++
++void fputs(const char *s, QIODevice &out)
++{
++ out.write(s);
++}
++// -- QtScxml
++
+ uint nameToBuiltinType(const QByteArray &name)
+ {
+ if (name.isEmpty())
+@@ -57,22 +82,25 @@
+ return nullptr;
+ }
+
+- Generator::Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes,
+- const QHash<QByteArray, QByteArray> &knownQObjectClasses,
+- const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile,
+- bool requireCompleteTypes)
+- : parser(moc),
+- out(outfile),
+- cdef(classDef),
+- metaTypes(metaTypes),
+- knownQObjectClasses(knownQObjectClasses),
+- knownGadgets(knownGadgets),
+- requireCompleteTypes(requireCompleteTypes)
+- {
+- if (cdef->superclassList.size())
+- purestSuperClass = cdef->superclassList.constFirst().classname;
++// -- QtScxml
++Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
++ const QHash<QByteArray, QByteArray> &knownQObjectClasses,
++ const QHash<QByteArray, QByteArray> &knownGadgets,
++ QIODevice &outfile,
++ bool requireCompleteTypes)
++ : out(outfile),
++ cdef(classDef),
++ metaTypes(metaTypes),
++ knownQObjectClasses(knownQObjectClasses),
++ knownGadgets(knownGadgets),
++ requireCompleteTypes(requireCompleteTypes)
++{
++ if (cdef->superclassList.size())
++ purestSuperClass = cdef->superclassList.constFirst().classname;
+ }
++// -- QtScxml
+
++#if 0 // -- QtScxml
+ static inline qsizetype lengthOfEscapeSequence(const QByteArray &s, qsizetype i)
+ {
+ if (s.at(i) != '\\' || i >= s.size() - 1)
+@@ -98,7 +126,7 @@
+
+ // Prints \a s to \a out, breaking it into lines of at most ColumnWidth. The
+ // opening and closing quotes are NOT included (it's up to the caller).
+-static void printStringWithIndentation(FILE *out, const QByteArray &s)
++static void printStringWithIndentation(QIODevice &out, const QByteArray &s) // -- QtScxml
+ {
+ static constexpr int ColumnWidth = 72;
+ const qsizetype len = s.size();
+@@ -116,6 +144,7 @@
+ idx += spanLen;
+ } while (idx < len);
+ }
++#endif // -- QtSxcml
+
+ void Generator::strreg(const QByteArray &s)
+ {
+@@ -270,12 +299,21 @@
+ qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData());
+ {
+ char comma = 0;
+- for (const QByteArray &str : strings) {
++// -- QtScxml
++ for (qsizetype i = 0, end = strings.size(); i < end; ++i) {
+ if (comma)
+ fputc(comma, out);
+- printStringWithIndentation(out, str);
++ fprintf(out, "\n {");
++ const QByteArray s = strings.at(i);
++ const qsizetype len = s.size();
++ for (qsizetype charPos = 0; charPos < len; ++charPos)
++ fprintf(out, "char(0x%.2x),", static_cast<quint8>(s.at(charPos)));
++ const bool isLast = (i == end - 1);
++ fprintf(out, "char(0)%s // %d: %s", isLast ? "}" : "},", i, s.constData());
+ comma = ',';
+ }
++// -- QtScxml
++
+ }
+ fprintf(out, "\n);\n"
+ "#else // !QT_MOC_HAS_STRINGDATA\n");
+@@ -298,8 +336,10 @@
+ qsizetype methodCount = 0;
+ if (qAddOverflow(cdef->signalList.size(), cdef->slotList.size(), &methodCount)
+ || qAddOverflow(cdef->methodList.size(), methodCount, &methodCount)) {
+- parser->error("internal limit exceeded: the total number of member functions"
++// -- QtScxml
++ qFatal("internal limit exceeded: the total number of member functions"
+ " (including signals and slots) is too big.");
++// -- QtScxml
+ }
+
+ fprintf(out, " %4" PRIdQSIZETYPE ", %4d, // methods\n", methodCount, methodCount ? index : 0);
+@@ -346,7 +386,9 @@
+ if (qAddOverflow(cdef->propertyList.size(), cdef->enumList.size(), &propEnumCount)
+ || qAddOverflow(propEnumCount, qsizetype(1), &propEnumCount)
+ || propEnumCount >= std::numeric_limits<int>::max()) {
+- parser->error("internal limit exceeded: number of property and enum metatypes is too big.");
++// -- QtScxml
++ qFatal("internal limit exceeded: number of property and enum metatypes is too big.");
++// -- QtScxml
+ }
+ int initialMetaTypeOffset = int(propEnumCount);
+
+@@ -585,7 +627,7 @@
+ fprintf(out, "\nvoid *%s::qt_metacast(const char *_clname)\n{\n", cdef->qualified.constData());
+ fprintf(out, " if (!_clname) return nullptr;\n");
+ fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n"
+- " return static_cast<void*>(this);\n",
++ " return static_cast<void*>(this);\n",
+ qualifiedClassNameIdentifier.constData());
+
+ // for all superclasses but the first one
+@@ -631,7 +673,9 @@
+ //
+ // Generate plugin meta data
+ //
++#if 0 // -- QtScxml
+ generatePluginMetaData();
++#endif // -- QtScxml
+
+ //
+ // Generate function to make sure the non-class signals exist in the parent classes
+@@ -1100,6 +1144,13 @@
+ const FunctionDef &f = methodList.at(methodindex);
+ Q_ASSERT(!f.normalizedType.isEmpty());
+ fprintf(out, " case %d: ", methodindex);
++ // -- QtScxml
++ if (f.implementation) {
++ fprintf(out, f.implementation, "_o", methodindex);
++ fprintf(out, " break;\n");
++ continue;
++ }
++ // -- QtScxml
+ if (f.normalizedType != "void")
+ fprintf(out, "{ %s _r = ", noRef(f.normalizedType).constData());
+ fprintf(out, "_t->");
+@@ -1178,6 +1229,10 @@
+ const FunctionDef &f = cdef->signalList.at(methodindex);
+ if (f.wasCloned || !f.inPrivateClass.isEmpty() || f.isStatic)
+ continue;
++ // -- QtScxml
++ if (f.mangledName.isEmpty())
++ continue;
++ // -- QtScxml
+ anythingUsed = true;
+ fprintf(out, " {\n");
+ fprintf(out, " using _t = %s (%s::*)(",f.type.rawName.constData() , cdef->classname.constData());
+@@ -1200,7 +1255,7 @@
+ else
+ fprintf(out, ");\n");
+ fprintf(out, " if (_t _q_method = &%s::%s; *reinterpret_cast<_t *>(_a[1]) == _q_method) {\n",
+- cdef->classname.constData(), f.name.constData());
++ cdef->classname.constData(), f.mangledName.constData()); // -- QtScxml
+ fprintf(out, " *result = %d;\n", methodindex);
+ fprintf(out, " return;\n");
+ fprintf(out, " }\n }\n");
+@@ -1295,8 +1350,11 @@
+ fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s().value(); break;\n",
+ propindex, p.type.constData(), prefix.constData(), p.bind.constData());
+ else if (!p.read.isEmpty())
+- fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n",
+- propindex, p.type.constData(), prefix.constData(), p.read.constData());
++ // -- QtScxml
++ fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s%s; break;\n",
++ propindex, p.type.constData(), prefix.constData(), p.read.constData(),
++ p.read.endsWith(')') ? "" : "()");
++ // -- QtScxml
+ else
+ fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s; break;\n",
+ propindex, p.type.constData(), prefix.constData(), p.member.constData());
+@@ -1428,6 +1486,10 @@
+ {
+ if (def->wasCloned || def->isAbstract)
+ return;
++// -- QtScxml
++ if (def->implementation)
++ return;
++// -- QtScxml
+ fprintf(out, "\n// SIGNAL %d\n%s %s::%s(",
+ index, def->type.name.constData(), cdef->qualified.constData(), def->name.constData());
+
+@@ -1476,10 +1538,8 @@
+ if (def->normalizedType == "void") {
+ fprintf(out, "nullptr");
+ } else {
+- if (def->returnTypeIsVolatile)
+- fprintf(out, "const_cast<void*>(reinterpret_cast<const volatile void*>(std::addressof(_t0)))");
+- else
+- fprintf(out, "const_cast<void*>(reinterpret_cast<const void*>(std::addressof(_t0)))");
++ // -- QtScxml removed unused returnTypeIsVolatile
++ fprintf(out, "const_cast<void*>(reinterpret_cast<const void*>(std::addressof(_t0)))");
+ }
+ int i;
+ for (i = 1; i < offset; ++i)
+@@ -1494,6 +1554,36 @@
+ fprintf(out, "}\n");
+ }
+
++// -- QtScxml
++void Generator::generateAccessorDefs()
++{
++ for (int propindex = 0; propindex < cdef->propertyList.size(); ++propindex) {
++ const PropertyDef &p = cdef->propertyList.at(propindex);
++ if (p.read.isEmpty() || p.mangledName.isEmpty())
++ continue;
++
++ fprintf(out, "bool %s::%s() const\n{\n return %s;\n}\n\n", cdef->classname.constData(),
++ p.mangledName.constData(), p.read.constData());
++ }
++}
++
++void Generator::generateSignalDefs()
++{
++ for (int methodindex = 0; methodindex < cdef->signalList.size(); ++methodindex) {
++ const FunctionDef &f = cdef->signalList.at(methodindex);
++ if (!f.implementation || f.mangledName.isEmpty())
++ continue;
++
++ fprintf(out, "void %s::%s(bool _t1)\n{\n", cdef->classname.constData(),
++ f.mangledName.constData());
++ fprintf(out, " void *_a[] = { nullptr, "
++ "const_cast<void*>(reinterpret_cast<const void*>(&_t1)) };\n ");
++ fprintf(out, f.implementation, "this", methodindex);
++ fprintf(out, "\n}\n\n");
++ }
++}
++
++#if 0
+ static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v);
+ static CborError jsonObjectToCbor(CborEncoder *parent, const QJsonObject &o)
+ {
+@@ -1629,7 +1719,11 @@
+
+ #define CBOR_ENCODER_WRITER_CONTROL 1
+ #define CBOR_ENCODER_WRITE_FUNCTION CborDevice::callback
++#endif
++// -- QtScxml
+
+ QT_END_NAMESPACE
+
++#if 0 // -- QtScxml
+ #include "cborencoder.c"
++#endif // -- QtScxml
diff --git a/tools/qscxmlc/moc_patches/generator.h.patch b/tools/qscxmlc/moc_patches/generator.h.patch
new file mode 100644
index 0000000..4fc3325
--- /dev/null
+++ b/tools/qscxmlc/moc_patches/generator.h.patch
@@ -0,0 +1,51 @@
+--- .upstream/generator.h 2023-06-22 20:40:43.078529554 +0200
++++ generator.h 2024-02-05 14:06:04.258179059 +0100
+@@ -6,23 +6,34 @@
+
+ #include "moc.h"
+
++// -- QtScxml
++#include <QtCore/qhash.h>
++#include <QtCore/qlist.h>
++#include <QtCore/qiodevice.h>
++// -- QtScxml
++
+ QT_BEGIN_NAMESPACE
+
+ class Generator
+ {
+- Moc *parser = nullptr;
+- FILE *out;
++ QIODevice &out; // -- QtScxml
+ ClassDef *cdef;
+ QList<uint> meta_data;
+
+ public:
+- Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes,
++ Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes,
+ const QHash<QByteArray, QByteArray> &knownQObjectClasses,
+- const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile = nullptr,
++ const QHash<QByteArray, QByteArray> &knownGadgets,
++ QIODevice &outfile, // -- QtScxml
+ bool requireCompleteTypes = false);
+ void generateCode();
+ qsizetype registeredStringsCount() { return strings.size(); };
+
++// -- QtScxml
++ void generateAccessorDefs();
++ void generateSignalDefs();
++// -- QtScxml
++
+ private:
+ bool registerableMetaType(const QByteArray &propertyType);
+ void registerClassInfoStrings();
+@@ -41,7 +52,9 @@
+ void generateMetacall();
+ void generateStaticMetacall();
+ void generateSignal(const FunctionDef *def, int index);
++#if 0 // -- QtScxml
+ void generatePluginMetaData();
++#endif // -- QtScxml
+ QMultiMap<QByteArray, int> automaticPropertyMetaTypesHelper();
+ QMap<int, QMultiMap<QByteArray, int>>
+ methodsWithAutomaticTypesHelper(const QList<FunctionDef> &methodList);
diff --git a/tools/qscxmlc/moc_patches/moc.cpp.patch b/tools/qscxmlc/moc_patches/moc.cpp.patch
new file mode 100644
index 0000000..7b55c65
--- /dev/null
+++ b/tools/qscxmlc/moc_patches/moc.cpp.patch
@@ -0,0 +1,29 @@
+--- .upstream/moc.cpp 2024-02-01 11:08:00.055494626 +0100
++++ moc.cpp 2024-02-05 14:06:04.258179059 +0100
+@@ -12,14 +12,15 @@
+ #include <QtCore/qdir.h>
+ #include <QtCore/qjsondocument.h>
+
+-// for normalizeTypeInternal
+-#include <private/qmetaobject_moc_p.h>
+-#include <private/qduplicatetracker_p.h>
++// -- QtScxml
++#include <QtCore/qjsonobject.h>
++// -- QtScxml
+
+ QT_BEGIN_NAMESPACE
+
+ using namespace Qt::StringLiterals;
+
++#if 0 // -- QtScxml
+ // only moc needs this function
+ static QByteArray normalizeType(const QByteArray &ba)
+ {
+@@ -1997,6 +1998,7 @@
+ }
+ }
+ }
++#endif // -- QtScxml
+
+ QJsonObject ClassDef::toJson() const
+ {
diff --git a/tools/qscxmlc/moc_patches/moc.h.patch b/tools/qscxmlc/moc_patches/moc.h.patch
new file mode 100644
index 0000000..dcdac6b
--- /dev/null
+++ b/tools/qscxmlc/moc_patches/moc.h.patch
@@ -0,0 +1,94 @@
+--- .upstream/moc.h 2024-02-05 14:10:55.937714571 +0100
++++ moc.h 2024-02-05 14:12:52.133597464 +0100
+@@ -4,14 +4,12 @@
+ #ifndef MOC_H
+ #define MOC_H
+
+-#include "parser.h"
+-#include <qstringlist.h>
+-#include <qmap.h>
+-#include <qjsondocument.h>
+-#include <qjsonarray.h>
+-#include <qjsonobject.h>
+-#include <qtyperevision.h>
+-#include <stdio.h>
++// -- QtScxml
++#include <QtCore/qmap.h>
++#include <QtCore/qpair.h>
++#include <QtCore/qjsondocument.h>
++#include <QtCore/qjsonarray.h>
++// -- QtScxml
+
+ #include <private/qtools_p.h>
+
+@@ -23,16 +21,18 @@
+ {
+ enum ReferenceType { NoReference, Reference, RValueReference, Pointer };
+
+- inline Type() : isVolatile(false), isScoped(false), firstToken(NOTOKEN), referenceType(NoReference) {}
++ inline Type() : isVolatile(false), isScoped(false), /* firstToken(NOTOKEN) -- QtScxml ,*/ referenceType(NoReference) {}
+ inline explicit Type(const QByteArray &_name)
+- : name(_name), rawName(name), isVolatile(false), isScoped(false), firstToken(NOTOKEN), referenceType(NoReference) {}
++ : name(_name), rawName(name), isVolatile(false), isScoped(false), /* firstToken(NOTOKEN) -- QtScxml ,*/ referenceType(NoReference) {}
+ QByteArray name;
+ //When used as a return type, the type name may be modified to remove the references.
+ // rawName is the type as found in the function signature
+ QByteArray rawName;
+ uint isVolatile : 1;
+ uint isScoped : 1;
++#if 0 // -- QtScxml
+ Token firstToken;
++#endif // -- QtScxml
+ ReferenceType referenceType;
+ };
+ Q_DECLARE_TYPEINFO(Type, Q_RELOCATABLE_TYPE);
+@@ -82,8 +82,9 @@
+ bool inlineCode = false;
+ bool wasCloned = false;
+
++#if 0 // -- QtScxml
+ bool returnTypeIsVolatile = false;
+-
++#endif // -- QtScxml
+ bool isCompat = false;
+ bool isInvokable = false;
+ bool isScriptable = false;
+@@ -97,6 +98,11 @@
+
+ QJsonObject toJson() const;
+ static void accessToJson(QJsonObject *obj, Access acs);
++
++// -- QtScxml
++ QByteArray mangledName;
++ const char *implementation = nullptr;
++// -- QtScxml
+ };
+ Q_DECLARE_TYPEINFO(FunctionDef, Q_RELOCATABLE_TYPE);
+
+@@ -124,6 +130,10 @@
+ qsizetype location = -1; // token index, used for error reporting
+
+ QJsonObject toJson() const;
++
++// -- QtScxml
++ QByteArray mangledName;
++// -- QtScxml
+ };
+ Q_DECLARE_TYPEINFO(PropertyDef, Q_RELOCATABLE_TYPE);
+
+@@ -204,6 +214,7 @@
+ };
+ Q_DECLARE_TYPEINFO(NamespaceDef, Q_RELOCATABLE_TYPE);
+
++#if 0 // -- QtScxml
+ class Moc : public Parser
+ {
+ public:
+@@ -293,6 +304,7 @@
+
+ void checkListSizes(const ClassDef &def);
+ };
++#endif // -- QtScxml
+
+ inline QByteArray noRef(const QByteArray &type)
+ {
diff --git a/tools/qscxmlc/moc_patches/outputrevision.h.patch b/tools/qscxmlc/moc_patches/outputrevision.h.patch
new file mode 100644
index 0000000..be3c2eb
--- /dev/null
+++ b/tools/qscxmlc/moc_patches/outputrevision.h.patch
@@ -0,0 +1,16 @@
+--- .upstream/outputrevision.h 2022-05-23 08:46:14.490945334 +0200
++++ outputrevision.h 2024-02-05 14:06:04.254179068 +0100
+@@ -4,7 +4,13 @@
+ #ifndef OUTPUTREVISION_H
+ #define OUTPUTREVISION_H
+
++#include <QtCore/qglobal.h> // -- QtScxml
++
++QT_BEGIN_NAMESPACE // -- QtScxml
++
+ // if the output revision changes, you MUST change it in qobjectdefs.h too
+ enum { mocOutputRevision = 68 }; // moc format output revision
+
++QT_END_NAMESPACE // -- QtScxml
++
+ #endif // OUTPUTREVISION_H
diff --git a/tools/qscxmlc/moc_patches/update_moc.sh b/tools/qscxmlc/moc_patches/update_moc.sh
new file mode 100755
index 0000000..410c9da
--- /dev/null
+++ b/tools/qscxmlc/moc_patches/update_moc.sh
@@ -0,0 +1,94 @@
+#!/bin/bash
+# Copyright (C) 2021 The Qt Company Ltd.
+# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+usage() {
+ cat <<EOF >&2
+
+Usage: update_moc [gu] [moc directory]
+
+The moc directory should be qtbase's moc source directory
+(absolute or relative). The script must be run from the directory
+containing the moc files (moc.h et. al).
+
+The script has two modes:
+
+'g' Generates updated patches of the current qtscxml-specific moc
+ changes. Use this when the qtscxml-specific parts in moc files
+ have changed and the patches should be updated accordingly.
+
+'u' Updates the moc from the upstream qtbase moc.
+ This mode gets the applicable qtbase moc files from the provided
+ directory, and updates their qtscxml copies by applying patches to them.
+ If you have not modified qtscxml moc code and just want to update the moc
+ code from upstream, this is the one you should use.
+
+Examples:
+moc_patches/update_moc g ../../../qtbase/src/tools/moc
+moc_patches/update_moc u ../../../qtbase/src/tools/moc
+
+EOF
+ die "$@"
+}
+
+checkFile () {
+ for f
+ do [[ -f "$f" ]] || die "Error: file \"$f\" does not exist."
+ done
+}
+
+warn () { echo "$@" >&2; }
+die () {
+ [[ -h .upstream ]] && rm .upstream
+ warn "$@"
+ exit 1
+}
+
+generate_patch() {
+ echo Generating patches recording how qscxmlc moc differs from upstream.
+
+ # Link the upstream moc files to create a patch file with filepaths
+ # that are independent of the actual used upstream moc location.
+ ln -s "$MOC_DIR" .upstream
+
+ for file in "${FILES[@]}"
+ do
+ checkFile "$file" ".upstream/$file"
+ diff -u ".upstream/$file" "$file" > "moc_patches/$file.patch"
+ echo Generated "moc_patches/$file.patch"
+ done
+ # tidy up
+ rm .upstream
+}
+
+update_moc() {
+ echo Updating qscxmlc moc from upstream by applying saved patches.
+
+ for file in "${FILES[@]}"
+ do
+ checkFile "moc_patches/$file.patch" "$MOC_DIR/$file"
+ echo Patching file: "$file" with "moc_patches/$file.patch"
+ # overwrite the current file from upstream
+ cp "$MOC_DIR/$file" "$file"
+ if patch "$file" "moc_patches/$file.patch"
+ then echo Patched "$file"
+ else warn "Please hand-patch $file; see $file.orig and $file.rej and tidy them away when you are done."
+ fi
+ done
+}
+
+MODE="$1"
+MOC_DIR="$2"
+FILES=( "outputrevision.h" "moc.cpp" "moc.h" "generator.h" "generator.cpp" )
+
+[[ -f moc_patches/update_moc.sh ]] || usage "Error: script must be run from the tools/qscxmlc/ directory."
+[[ -n "$MOC_DIR" ]] || usage "Error: You did not specify a moc directory."
+[[ -d "$MOC_DIR" ]] || usage "Error: moc directory \"$MOC_DIR\" does not exist."
+
+case "$MODE" in
+ g) generate_patch ;;
+ u) update_moc ;;
+ *) usage "Error: mode \"$MODE\" is not recognized." ;;
+esac
+
+echo Done
diff --git a/tools/qscxmlc/outputrevision.h b/tools/qscxmlc/outputrevision.h
index 89a0b6e..c170203 100644
--- a/tools/qscxmlc/outputrevision.h
+++ b/tools/qscxmlc/outputrevision.h
@@ -1,41 +1,16 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef OUTPUTREVISION_H
#define OUTPUTREVISION_H
-#include <QtCore/qglobal.h>
+#include <QtCore/qglobal.h> // -- QtScxml
-QT_BEGIN_NAMESPACE
+QT_BEGIN_NAMESPACE // -- QtScxml
// if the output revision changes, you MUST change it in qobjectdefs.h too
-enum { mocOutputRevision = 67 }; // moc format output revision
+enum { mocOutputRevision = 68 }; // moc format output revision
-QT_END_NAMESPACE
+QT_END_NAMESPACE // -- QtScxml
#endif // OUTPUTREVISION_H
diff --git a/tools/qscxmlc/qscxmlc.cpp b/tools/qscxmlc/qscxmlc.cpp
index d83e786..fdf89a1 100644
--- a/tools/qscxmlc/qscxmlc.cpp
+++ b/tools/qscxmlc/qscxmlc.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtScxml/private/qscxmlcompiler_p.h>
#include <QtScxml/qscxmltabledata.h>
@@ -35,7 +10,7 @@
#include <QCommandLineParser>
#include <QFile>
#include <QFileInfo>
-#include <QTextCodec>
+#include <QStringConverter>
QT_BEGIN_NAMESPACE
@@ -68,17 +43,17 @@ int write(TranslationUnit *tu)
}
// Make sure it outputs UTF-8, as that is what C++ expects.
- QTextCodec *utf8 = QTextCodec::codecForName("UTF-8");
+ auto utf8 = QStringConverter::encodingForName("UTF-8");
if (!utf8) {
- errs << QStringLiteral("Error: cannot find a QTextCodec for generating UTF-8.");
+ errs << QStringLiteral("Error: cannot find a QStringConverter for generating UTF-8.");
return NoTextCodecError;
}
QTextStream h(&outH);
- h.setCodec(utf8);
+ h.setEncoding(utf8.value());
h.setGenerateByteOrderMark(true);
QTextStream c(&outCpp);
- c.setCodec(utf8);
+ c.setEncoding(utf8.value());
c.setGenerateByteOrderMark(true);
CppDumper dumper(h, c);
dumper.dump(tu);
@@ -93,7 +68,7 @@ static void collectAllDocuments(DocumentModel::ScxmlDocument *doc,
QList<DocumentModel::ScxmlDocument *> *docs)
{
docs->append(doc);
- for (DocumentModel::ScxmlDocument *subDoc : qAsConst(doc->allSubDocuments))
+ for (DocumentModel::ScxmlDocument *subDoc : std::as_const(doc->allSubDocuments))
collectAllDocuments(subDoc, docs);
}
@@ -138,12 +113,12 @@ int run(const QStringList &arguments)
const QStringList inputFiles = cmdParser.positionalArguments();
- if (inputFiles.count() < 1) {
+ if (inputFiles.size() < 1) {
errs << QCoreApplication::translate("main", "Error: no input file.") << Qt::endl;
cmdParser.showHelp(NoInputFilesError);
}
- if (inputFiles.count() > 1) {
+ if (inputFiles.size() > 1) {
errs << QCoreApplication::translate("main", "Error: unexpected argument(s): %1")
.arg(inputFiles.mid(1).join(QLatin1Char(' '))) << Qt::endl;
cmdParser.showHelp(NoInputFilesError);
@@ -217,7 +192,7 @@ int run(const QStringList &arguments)
docs.pop_front();
- for (DocumentModel::ScxmlDocument *doc : qAsConst(docs)) {
+ for (DocumentModel::ScxmlDocument *doc : std::as_const(docs)) {
auto name = doc->root->name;
auto prefix = name;
if (name.isEmpty()) {
diff --git a/tools/qscxmlc/qscxmlc.h b/tools/qscxmlc/qscxmlc.h
index 81c2427..160ad76 100644
--- a/tools/qscxmlc/qscxmlc.h
+++ b/tools/qscxmlc/qscxmlc.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QSCXMLC_H
#define QSCXMLC_H
@@ -43,7 +7,6 @@
#include <QtCore/qglobal.h>
QT_BEGIN_NAMESPACE
-class QStringList;
int run(const QStringList &arguments);
diff --git a/tools/qscxmlc/qscxmlc.pri b/tools/qscxmlc/qscxmlc.pri
deleted file mode 100644
index 4c7c991..0000000
--- a/tools/qscxmlc/qscxmlc.pri
+++ /dev/null
@@ -1,32 +0,0 @@
-DEFINES += BUILD_QSCXMLC
-
-SOURCES += \
- $$PWD/generator.cpp \
- $$PWD/qscxmlc.cpp \
- $$PWD/scxmlcppdumper.cpp
-
-HEADERS += \
- $$PWD/moc.h \
- $$PWD/generator.h \
- $$PWD/outputrevision.h \
- $$PWD/qscxmlc.h \
- $$PWD/utils.h \
- $$PWD/scxmlcppdumper.h
-
-HEADERS += \
- $$PWD/../../src/scxml/qscxmlcompiler.h \
- $$PWD/../../src/scxml/qscxmlcompiler_p.h \
- $$PWD/../../src/scxml/qscxmlglobals.h \
- $$PWD/../../src/scxml/qscxmlexecutablecontent.h \
- $$PWD/../../src/scxml/qscxmlexecutablecontent_p.h \
- $$PWD/../../src/scxml/qscxmlerror.h \
- $$PWD/../../src/scxml/qscxmltabledata.h
-
-SOURCES += \
- $$PWD/../../src/scxml/qscxmlcompiler.cpp \
- $$PWD/../../src/scxml/qscxmlexecutablecontent.cpp \
- $$PWD/../../src/scxml/qscxmlerror.cpp \
- $$PWD/../../src/scxml/qscxmltabledata.cpp
-
-DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
-INCLUDEPATH *= $$QT.scxml.includes $$QT.scxml_private.includes
diff --git a/tools/qscxmlc/qscxmlc.pro b/tools/qscxmlc/qscxmlc.pro
deleted file mode 100644
index 7620d3d..0000000
--- a/tools/qscxmlc/qscxmlc.pro
+++ /dev/null
@@ -1,16 +0,0 @@
-option(host_build)
-
-QT = core-private
-
-include(qscxmlc.pri)
-
-TARGET = qscxmlc
-CONFIG += console c++11
-
-SOURCES += \
- main.cpp
-
-load(qt_tool)
-load(resources)
-
-RESOURCES += templates.qrc
diff --git a/tools/qscxmlc/scxmlcppdumper.cpp b/tools/qscxmlc/scxmlcppdumper.cpp
index 1aca09e..765498c 100644
--- a/tools/qscxmlc/scxmlcppdumper.cpp
+++ b/tools/qscxmlc/scxmlcppdumper.cpp
@@ -1,30 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "scxmlcppdumper.h"
#include "generator.h"
@@ -67,7 +42,7 @@ QString cEscape(const QString &str)
{
QString res;
int lastI = 0;
- for (int i = 0; i < str.length(); ++i) {
+ for (int i = 0; i < str.size(); ++i) {
QChar c = str.at(i);
if (c < QLatin1Char(' ') || c == QLatin1Char('\\') || c == QLatin1Char('\"')) {
res.append(str.mid(lastI, i - lastI));
@@ -109,27 +84,26 @@ static void genTemplate(QTextStream &out, const QString &filename, const Replace
qFatal("Unable to open template '%s'", qPrintable(filename));
}
Q_ASSERT(file.compressionAlgorithm() == QResource::NoCompression);
- QByteArray data;
- data = QByteArray::fromRawData(reinterpret_cast<const char *>(file.data()),
- int(file.size()));
- const QString t = QString::fromLatin1(data);
- data.clear();
+ const QString data = QString::fromLatin1(
+ QByteArray::fromRawData(reinterpret_cast<const char *>(file.data()), int(file.size()))
+ );
+ const QStringView t { data };
int start = 0;
for (int openIdx = t.indexOf(QStringLiteral("${"), start); openIdx >= 0; openIdx =
t.indexOf(QStringLiteral("${"), start)) {
- out << t.midRef(start, openIdx - start);
+ out << t.mid(start, openIdx - start);
openIdx += 2;
const int closeIdx = t.indexOf(QLatin1Char('}'), openIdx);
Q_ASSERT(closeIdx >= openIdx);
- QString key = t.mid(openIdx, closeIdx - openIdx);
+ QString key = t.mid(openIdx, closeIdx - openIdx).toString();
if (!replacements.contains(key)) {
qFatal("Replacing '%s' failed: no replacement found", qPrintable(key));
}
out << replacements.value(key);
start = closeIdx + 1;
}
- out << t.midRef(start);
+ out << t.mid(start);
}
static const char *headerStart =
@@ -163,7 +137,7 @@ static void generateList(QString &out, std::function<QString(int)> next)
if (i != 0)
line += QLatin1Char(',');
- if (line.length() + nr.length() + 1 > maxLineLength) {
+ if (line.size() + nr.size() + 1 > maxLineLength) {
out += line + QLatin1Char('\n');
line.clear();
} else if (i != 0) {
@@ -267,8 +241,8 @@ void generateTables(const GeneratedTableData &td, Replacements &replacements)
return QString();
const int length = strings.at(idx).size();
- const QString str = QStringLiteral("STR_LIT(%1, %2, %3)").arg(
- QString::number(idx), QString::number(ucharCount), QString::number(length));
+ const QString str = QStringLiteral("%1, %2").arg(
+ QString::number(ucharCount), QString::number(length));
ucharCount += length + 1;
return str;
});
@@ -365,8 +339,8 @@ void generateCppDataModelEvaluators(const GeneratedTableData::DataModelInfo &inf
int createFactoryId(QStringList &factories, const QString &className,
const QString &namespacePrefix,
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &namelist,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters)
+ const QList<QScxmlExecutableContent::StringId> &namelist,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters)
{
const int idx = factories.size();
@@ -421,10 +395,10 @@ void CppDumper::dump(TranslationUnit *unit)
}
QStringList classNames;
- QVector<GeneratedTableData> tables;
- QVector<GeneratedTableData::MetaDataInfo> metaDataInfos;
- QVector<GeneratedTableData::DataModelInfo> dataModelInfos;
- QVector<QStringList> factories;
+ QList<GeneratedTableData> tables;
+ QList<GeneratedTableData::MetaDataInfo> metaDataInfos;
+ QList<GeneratedTableData::DataModelInfo> dataModelInfos;
+ QList<QStringList> factories;
auto docs = m_translationUnit->allDocuments;
tables.resize(docs.size());
metaDataInfos.resize(tables.size());
@@ -438,8 +412,8 @@ void CppDumper::dump(TranslationUnit *unit)
GeneratedTableData::build(doc, &tables[i], metaDataInfo, &dataModelInfos[i],
[this, &factories, i, &classnameForDocument, &namespacePrefix](
const QScxmlExecutableContent::InvokeInfo &invokeInfo,
- const QVector<QScxmlExecutableContent::StringId> &names,
- const QVector<QScxmlExecutableContent::ParameterInfo> &parameters,
+ const QList<QScxmlExecutableContent::StringId> &names,
+ const QList<QScxmlExecutableContent::ParameterInfo> &parameters,
const QSharedPointer<DocumentModel::ScxmlDocument> &content) -> int {
QString className;
if (invokeInfo.expr == QScxmlExecutableContent::NoEvaluator) {
@@ -538,13 +512,13 @@ void CppDumper::writeImplStart()
<< Qt::endl;
QStringList includes;
- for (DocumentModel::ScxmlDocument *doc : qAsConst(m_translationUnit->allDocuments)) {
+ for (DocumentModel::ScxmlDocument *doc : std::as_const(m_translationUnit->allDocuments)) {
switch (doc->root->dataModel) {
case DocumentModel::Scxml::NullDataModel:
includes += l("QScxmlNullDataModel");
break;
case DocumentModel::Scxml::JSDataModel:
- includes += l("QScxmlEcmaScriptDataModel");
+ includes += l("QScxmlDataModel");
break;
case DocumentModel::Scxml::CppDataModel:
includes += doc->root->cppDataModelHeaderName;
@@ -559,8 +533,10 @@ void CppDumper::writeImplStart()
cpp << l("#include \"") << headerName << l("\"") << Qt::endl;
cpp << Qt::endl
<< QStringLiteral("#include <qscxmlinvokableservice.h>") << Qt::endl
- << QStringLiteral("#include <qscxmltabledata.h>") << Qt::endl;
- for (const QString &inc : qAsConst(includes)) {
+ << QStringLiteral("#include <qscxmltabledata.h>") << Qt::endl
+ << QStringLiteral("#include <QtCore/qtmochelpers.h>") << Qt::endl;
+
+ for (const QString &inc : std::as_const(includes)) {
cpp << l("#include <") << inc << l(">") << Qt::endl;
}
cpp << Qt::endl
@@ -585,8 +561,11 @@ void CppDumper::writeImplBody(const GeneratedTableData &table,
dataModelInitialization = l("stateMachine.setDataModel(&dataModel);");
break;
case DocumentModel::Scxml::JSDataModel:
- dataModelField = l("QScxmlEcmaScriptDataModel dataModel;");
- dataModelInitialization = l("stateMachine.setDataModel(&dataModel);");
+ dataModelField = l("std::unique_ptr<QScxmlDataModel> dataModel;");
+ dataModelInitialization = l(
+ " dataModel.reset(QScxmlDataModel::createScxmlDataModel(QStringLiteral(\"ecmascriptdatamodel\")));\n"
+ " stateMachine.setDataModel(dataModel.get());\n"
+ );
break;
case DocumentModel::Scxml::CppDataModel:
dataModelField = QStringLiteral("// Data model %1 is set from outside.").arg(
@@ -675,7 +654,7 @@ QString CppDumper::mangleIdentifier(const QString &str)
}
}
- for (int ei = str.length(); i != ei; ++i) {
+ for (int ei = str.size(); i != ei; ++i) {
auto c = str.at(i);
if ((c >= QLatin1Char('0') && c <= QLatin1Char('9')) || isNonDigit(c)) {
mangled += c;
@@ -750,7 +729,11 @@ QString CppDumper::generateMetaObject(const QString &className,
ClassDef classDef;
classDef.classname = className.toUtf8();
classDef.qualified = classDef.classname;
- classDef.superclassList << qMakePair(QByteArray("QScxmlStateMachine"), FunctionDef::Public);
+ classDef.superclassList << SuperClass {
+ QByteArray("QScxmlStateMachine"),
+ QByteArray(QT_STRINGIFY(QT_PREPEND_NAMESPACE(QScxmlStateMachine))),
+ FunctionDef::Public
+ };
classDef.hasQObject = true;
FunctionDef constructor;
constructor.name = className.toUtf8();
@@ -795,7 +778,6 @@ QString CppDumper::generateMetaObject(const QString &className,
signal.arguments << arg;
classDef.signalList << signal;
- ++classDef.notifyableProperties;
PropertyDef prop;
prop.name = stateName.toUtf8();
if (m_translationUnit->stateMethods)
diff --git a/tools/qscxmlc/scxmlcppdumper.h b/tools/qscxmlc/scxmlcppdumper.h
index 35849c0..a3123b0 100644
--- a/tools/qscxmlc/scxmlcppdumper.h
+++ b/tools/qscxmlc/scxmlcppdumper.h
@@ -1,36 +1,10 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef SCXMLCPPDUMPER_H
#define SCXMLCPPDUMPER_H
-#include "qscxmlglobals.h"
-
+#include <QtScxml/qscxmlglobals.h>
#include <QtScxml/private/qscxmlcompiler_p.h>
#include <QtScxml/private/qscxmltabledata_p.h>
diff --git a/tools/qscxmlc/templates.qrc b/tools/qscxmlc/templates.qrc
deleted file mode 100644
index a00f24e..0000000
--- a/tools/qscxmlc/templates.qrc
+++ /dev/null
@@ -1,7 +0,0 @@
-<RCC>
- <qresource prefix="/">
- <file compression-algorithm="none">data.t</file>
- <file compression-algorithm="none">decl.t</file>
- <file compression-algorithm="none">cppdatamodel.t</file>
- </qresource>
-</RCC>
diff --git a/tools/qscxmlc/utils.h b/tools/qscxmlc/utils.h
index 58cf924..358780a 100644
--- a/tools/qscxmlc/utils.h
+++ b/tools/qscxmlc/utils.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtScxml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef UTILS_H
#define UTILS_H