diff options
Diffstat (limited to 'src/tools/moc')
25 files changed, 1351 insertions, 1591 deletions
diff --git a/src/tools/moc/CMakeLists.txt b/src/tools/moc/CMakeLists.txt index 88dce045f8..b98b7ab4e9 100644 --- a/src/tools/moc/CMakeLists.txt +++ b/src/tools/moc/CMakeLists.txt @@ -1,4 +1,5 @@ -# Generated from moc.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## moc Tool: @@ -6,10 +7,11 @@ qt_get_tool_target_name(target_name moc) qt_internal_add_tool(${target_name} - BOOTSTRAP + TRY_RUN + CORE_LIBRARY Bootstrap TARGET_DESCRIPTION "Qt Meta Object Compiler" INSTALL_DIR "${INSTALL_LIBEXECDIR}" - TOOLS_TARGET Core # special case + TOOLS_TARGET Core SOURCES cbordevice.h collectjson.cpp collectjson.h @@ -19,7 +21,6 @@ qt_internal_add_tool(${target_name} outputrevision.h parser.cpp parser.h preprocessor.cpp preprocessor.h - # qdatetime_p.h special case remove symbols.h token.cpp token.h utils.h @@ -27,17 +28,15 @@ qt_internal_add_tool(${target_name} QT_MOC QT_NO_CAST_FROM_ASCII QT_NO_CAST_FROM_BYTEARRAY - QT_NO_COMPRESS QT_NO_FOREACH + QT_NO_QPAIR + QT_USE_NODISCARD_FILE_OPEN INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} ../../3rdparty/tinycbor/src ../shared ) - -#### Keys ignored in scope 1:.:.:moc.pro:<TRUE>: -# QMAKE_TARGET_DESCRIPTION = "Qt Meta Object Compiler" -# _OPTION = "host_build" +qt_internal_return_unless_building_tools() ## Scopes: ##################################################################### diff --git a/src/tools/moc/cbordevice.h b/src/tools/moc/cbordevice.h index dbfc537dd2..7668e4c0be 100644 --- a/src/tools/moc/cbordevice.h +++ b/src/tools/moc/cbordevice.h @@ -1,34 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2018 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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) 2018 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef CBORDEVICE_H #define CBORDEVICE_H +#include <QtCore/qtypes.h> + #include <memory> #include <stdio.h> diff --git a/src/tools/moc/collectjson.cpp b/src/tools/moc/collectjson.cpp index 6577a3216b..d542e2abc4 100644 --- a/src/tools/moc/collectjson.cpp +++ b/src/tools/moc/collectjson.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite 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) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include <qfile.h> #include <qjsonarray.h> @@ -85,7 +60,7 @@ int collectJson(const QStringList &jsonFiles, const QString &outputFile, bool sk QStringList jsonFilesSorted = jsonFiles; jsonFilesSorted.sort(); - for (const QString &jsonFile : qAsConst(jsonFilesSorted)) { + for (const QString &jsonFile : std::as_const(jsonFilesSorted)) { QFile f(jsonFile); if (!f.open(QIODevice::ReadOnly)) { fprintf(stderr, "Error opening %s for reading\n", qPrintable(jsonFile)); diff --git a/src/tools/moc/collectjson.h b/src/tools/moc/collectjson.h index 3a33952a54..b16ae61519 100644 --- a/src/tools/moc/collectjson.h +++ b/src/tools/moc/collectjson.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef COLLECTJSON_H #define COLLECTJSON_H diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp index a21e44ba8f..1c6604a96e 100644 --- a/src/tools/moc/generator.cpp +++ b/src/tools/moc/generator.cpp @@ -1,32 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com> -** Copyright (C) 2018 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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" #include "cbordevice.h" @@ -48,6 +23,8 @@ QT_BEGIN_NAMESPACE +using namespace QtMiscUtils; + uint nameToBuiltinType(const QByteArray &name) { if (name.isEmpty()) @@ -80,11 +57,12 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING) return nullptr; } - Generator::Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, + Generator::Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile, bool requireCompleteTypes) - : out(outfile), + : parser(moc), + out(outfile), cdef(classDef), metaTypes(metaTypes), knownQObjectClasses(knownQObjectClasses), @@ -92,32 +70,53 @@ QT_FOR_EACH_STATIC_TYPE(RETURN_METATYPENAME_STRING) requireCompleteTypes(requireCompleteTypes) { if (cdef->superclassList.size()) - purestSuperClass = cdef->superclassList.constFirst().first; + purestSuperClass = cdef->superclassList.constFirst().classname; } -static inline int lengthOfEscapeSequence(const QByteArray &s, int i) +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(FILE *out, const QByteArray &s) +{ + 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); +} + void Generator::strreg(const QByteArray &s) { if (!strings.contains(s)) @@ -126,7 +125,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; } @@ -137,8 +136,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; } @@ -175,14 +174,14 @@ bool Generator::registerableMetaType(const QByteArray &propertyType) #undef STREAM_1ARG_TEMPLATE ; for (const QByteArray &oneArgTemplateType : oneArgTemplates) { - QByteArray ba = oneArgTemplateType + "<"; + const QByteArray ba = oneArgTemplateType + "<"; if (propertyType.startsWith(ba) && propertyType.endsWith(">")) { - const int argumentSize = propertyType.size() - oneArgTemplateType.size() - 1 + 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); } } @@ -195,12 +194,28 @@ 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 isQObject = (cdef->classname == "QObject"); @@ -209,8 +224,7 @@ void Generator::generateCode() // 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; } @@ -237,128 +251,58 @@ void Generator::generateCode() 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, " const uint offsetsAndSize[%d];\n", int(strings.size()*2)); - { - 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, " char stringdata%d[%d];\n", stringDataCounter++, stringDataLength - thisLength); - stringDataLength = thisLength; - } - } - fprintf(out, " 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(ofs, len) \\\n" - " uint(offsetof(qt_meta_stringdata_%s_t, stringdata0) + ofs), len \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)", idx, int(str.length())); - if (i != strings.size() - 1) - fputc(',', out); - const QByteArray comment = str.length() > 32 ? str.left(29) + "..." : str; - fprintf(out, " // \"%s\"\n", comment.size() ? 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; + for (const QByteArray &str : strings) { + if (comma) + fputc(comma, out); + printStringWithIndentation(out, str); + comma = ','; } - fprintf(out, "\n },\n"); } - -// -// Build stringdata array -// - fprintf(out, " \""); - int col = 0; - int len = 0; - int stringDataLength = 0; - for (int i = 0; i < strings.size(); ++i) { - QByteArray s = strings.at(i); - len = s.length(); - stringDataLength += len + 1; - if (stringDataLength >= constCharArraySizeLimit) { - fprintf(out, "\",\n \""); - stringDataLength = len + 1; - col = 0; - } else if (i) - fputs("\\0", out); // add \0 at the end of each string - - if (col && col + len >= 72) { - fprintf(out, "\"\n \""); - col = 0; - } else if (len && s.at(0) >= '0' && s.at(0) <= '9') { - fprintf(out, "\"\""); - len += 2; - } - int idx = 0; - while (idx < s.length()) { - if (idx > 0) { - col = 0; - fprintf(out, "\"\n \""); - } - int spanLen = qMin(70, s.length() - idx); - // don't cut escape sequences at the end of a line - int backSlashPos = s.lastIndexOf('\\', idx + spanLen - 1); - if (backSlashPos >= idx) { - int escapeLen = lengthOfEscapeSequence(s, backSlashPos); - spanLen = qBound(spanLen, backSlashPos + escapeLen - idx, s.length() - idx); - } - fprintf(out, "%.*s", spanLen, s.constData() + idx); - idx += spanLen; - col += spanLen; - } - col += len + 2; - } - -// Terminate stringdata struct - fprintf(out, "\"\n};\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", int(cdef->classInfoList.count()), int(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)) { + parser->error("internal limit exceeded: the total number of member functions" + " (including signals and slots) is too big."); + } - int methodCount = cdef->signalList.count() + cdef->slotList.count() + cdef->methodList.count(); - fprintf(out, " %4d, %4d, // methods\n", methodCount, methodCount ? index : 0); + fprintf(out, " %4" PRIdQSIZETYPE ", %4d, // methods\n", methodCount, methodCount ? index : 0); index += methodCount * QMetaObjectPrivate::IntsPerMethod; if (cdef->revisionedMethods) index += methodCount; @@ -369,16 +313,17 @@ 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", int(cdef->propertyList.count()), int(cdef->propertyList.count() ? index : 0)); - index += cdef->propertyList.count() * QMetaObjectPrivate::IntsPerProperty; - fprintf(out, " %4d, %4d, // enums/sets\n", int(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 += 5 + (cdef->enumList.at(i).values.count() * 2); - fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? int(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; @@ -388,7 +333,7 @@ void Generator::generateCode() flags |= PropertyAccessInStaticMetaCall; } fprintf(out, " %4d, // flags\n", flags); - fprintf(out, " %4d, // signalCount\n", int(cdef->signalList.count())); + fprintf(out, " %4d, // signalCount\n", int(cdef->signalList.size())); // @@ -396,8 +341,14 @@ void Generator::generateCode() // generateClassInfos(); - // all property metatypes, + 1 for the type of the current class itself - int initialMetaTypeOffset = cdef->propertyList.count() + 1; + 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()) { + parser->error("internal limit exceeded: number of property and enum metatypes is too big."); + } + int initialMetaTypeOffset = int(propEnumCount); // // Build signals array first, otherwise the signal indices would be wrong @@ -454,30 +405,20 @@ void Generator::generateCode() fprintf(out, "\n 0 // eod\n};\n\n"); // -// Generate internal qt_static_metacall() function -// - const bool hasStaticMetaCall = - (cdef->hasQObject || !cdef->methodList.isEmpty() - || !cdef->propertyList.isEmpty() || !cdef->constructorList.isEmpty()); - if (hasStaticMetaCall) - generateStaticMetacall(); - -// // Build extra array // QList<QByteArray> extraList; 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; @@ -488,7 +429,7 @@ void Generator::generateCode() 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); @@ -514,7 +455,7 @@ void Generator::generateCode() for (auto it = cdef->enumDeclarations.keyBegin(), end = cdef->enumDeclarations.keyEnd(); it != end; ++it) { const QByteArray &enumKey = *it; - int s = enumKey.lastIndexOf("::"); + const qsizetype s = enumKey.lastIndexOf("::"); if (s > 0) { QByteArray scope = enumKey.left(s); if (scope != "Qt" && !qualifiedNameEquals(cdef->qualified, scope) && !extraList.contains(scope)) @@ -527,28 +468,29 @@ void Generator::generateCode() // if (!extraList.isEmpty()) { - fprintf(out, "static const QMetaObject::SuperData qt_meta_extradata_%s[] = {\n", + fprintf(out, "Q_CONSTINIT static const QMetaObject::SuperData qt_meta_extradata_%s[] = {\n", qualifiedClassNameIdentifier.constData()); - for (int i = 0; i < extraList.count(); ++i) { - fprintf(out, " QMetaObject::SuperData::link<%s::staticMetaObject>(),\n", extraList.at(i).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 // - 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,\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()); + fprintf(out, " QtPrivate::MetaObjectForType<%s>::value,\n", purestSuperClass.constData()); else fprintf(out, " nullptr,\n"); - fprintf(out, " qt_meta_stringdata_%s.offsetsAndSize,\n" + fprintf(out, " qt_meta_stringdata_%s.offsetsAndSizes,\n" " qt_meta_data_%s,\n", qualifiedClassNameIdentifier.constData(), qualifiedClassNameIdentifier.constData()); if (hasStaticMetaCall) @@ -561,63 +503,75 @@ void Generator::generateCode() else fprintf(out, " qt_meta_extradata_%s,\n", qualifiedClassNameIdentifier.constData()); - bool needsComma = false; + 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\n", qualifiedClassNameIdentifier.constData()); - needsComma = true; + fprintf(out, " qt_incomplete_metaTypeArray<qt_meta_stringdata_%s_t", qualifiedClassNameIdentifier.constData()); + comma = ","; } else { - fprintf(out, "qt_metaTypeArray<\n"); + fprintf(out, " qt_metaTypeArray<"); } // metatypes for properties - for (int i = 0; i < cdef->propertyList.count(); ++i) { - const PropertyDef &p = cdef->propertyList.at(i); - if (requireCompleteness) - fprintf(out, "%s%s", needsComma ? ", " : "", p.type.data()); - else - fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::true_type>", needsComma ? ", " : "", p.type.data()); - needsComma = true; + 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 = ","; + } + + // 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"; - if (requireCompleteness) - fprintf(out, "%s%s", needsComma ? ", " : "", ownType); - else - fprintf(out, "%sQtPrivate::TypeAndForceComplete<%s, std::true_type>", needsComma ? ", " : "", ownType); + fprintf(out, "%s\n // Q_OBJECT / Q_GADGET\n %s", + comma, stringForType(ownType, true).constData()); + comma = ","; // metatypes for all exposed methods - // no need to check for needsComma any longer, as we always need one due to the classname being present - for (const QList<FunctionDef> &methodContainer : - { cdef->signalList, cdef->slotList, cdef->methodList }) { - for (int i = 0; i< methodContainer.count(); ++i) { - const FunctionDef& fdef = methodContainer.at(i); - if (requireCompleteness) - fprintf(out, ", %s", fdef.type.name.data()); - else - fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", fdef.type.name.data()); - for (const auto &argument: fdef.arguments) { - if (requireCompleteness) - fprintf(out, ", %s", argument.type.name.data()); - else - fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", argument.type.name.data()); - } + // 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()); } - fprintf(out, "\n"); } - for (int i = 0; i< cdef->constructorList.count(); ++i) { - const FunctionDef& fdef = cdef->constructorList.at(i); + + // 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) { - if (requireCompleteness) - fprintf(out, ", %s", argument.type.name.data()); - else - fprintf(out, ", QtPrivate::TypeAndForceComplete<%s, std::false_type>", argument.type.name.data()); + fprintf(out, "%s\n %s", comma, + stringForType(argument.type.name, false).constData()); + comma = ","; } } - fprintf(out, "\n"); - fprintf(out, ">,\n"); + fprintf(out, "\n >,\n"); fprintf(out, " nullptr\n} };\n\n"); +// +// Generate internal qt_static_metacall() function +// + if (hasStaticMetaCall) + generateStaticMetacall(); + if (!cdef->hasQObject) return; @@ -633,18 +587,24 @@ void Generator::generateCode() fprintf(out, " if (!strcmp(_clname, qt_meta_stringdata_%s.stringdata0))\n" " return static_cast<void*>(this);\n", qualifiedClassNameIdentifier.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*>(this);\n", - cname, cname); + + // 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, "this%s;\n", QByteArray(j + 1, ')').constData()); } @@ -665,8 +625,8 @@ 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); // // Generate plugin meta data @@ -677,12 +637,29 @@ void Generator::generateCode() // Generate function to make sure the non-class signals exist in the parent classes // if (!cdef->nonClassSignalList.isEmpty()) { - fprintf(out, "// If you get a compile error in this function it can be because either\n"); - fprintf(out, "// a) You are using a NOTIFY signal that does not exist. Fix it.\n"); - fprintf(out, "// b) You are using a NOTIFY signal that does exist (in a parent class) but has a non-empty parameter list. This is a moc limitation.\n"); - fprintf(out, "[[maybe_unused]] static void checkNotifySignalValidity_%s(%s *t) {\n", qualifiedClassNameIdentifier.constData(), cdef->qualified.constData()); - for (const QByteArray &nonClassSignal : qAsConst(cdef->nonClassSignalList)) - fprintf(out, " t->%s();\n", nonClassSignal.constData()); + 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"); } } @@ -690,8 +667,7 @@ void Generator::generateCode() 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); } @@ -704,25 +680,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); @@ -743,9 +713,7 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu return; fprintf(out, "\n // %ss: name, argc, parameters, tag, flags, initial metatype offsets\n", functype); - for (int i = 0; i < list.count(); ++i) { - const FunctionDef &f = list.at(i); - + for (const FunctionDef &f : list) { QByteArray comment; uint flags = type; if (f.access == FunctionDef::Private) { @@ -780,7 +748,7 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu comment.append(" | MethodIsConst "); } - int argc = f.arguments.count(); + 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()); @@ -792,12 +760,10 @@ void Generator::generateFunctions(const QList<FunctionDef> &list, const char *fu 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) @@ -805,25 +771,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"); } @@ -856,8 +819,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); @@ -870,10 +832,9 @@ void Generator::generateProperties() // Create meta data // - if (cdef->propertyList.count()) - fprintf(out, "\n // properties: name, type, flags\n"); - for (int i = 0; i < cdef->propertyList.count(); ++i) { - const PropertyDef &p = cdef->propertyList.at(i); + if (cdef->propertyList.size()) + fprintf(out, "\n // properties: name, type, flags, notifyId, revision\n"); + for (const PropertyDef &p : std::as_const(cdef->propertyList)) { uint flags = Invalid; if (!isBuiltinType(p.type)) flags |= EnumOrFlag; @@ -917,7 +878,7 @@ void Generator::generateProperties() int notifyId = p.notifyId; if (p.notifyId < -1) { // signal is in parent class - const int indexInStrings = strings.indexOf(p.notify); + const int indexInStrings = int(strings.indexOf(p.notify)); notifyId = indexInStrings | IsUnresolvedSignal; } fprintf(out, ", 0x%.8x, uint(%d), %d,\n", flags, notifyId, p.revision); @@ -926,13 +887,12 @@ void Generator::generateProperties() 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); if (!e.enumName.isNull()) strreg(e.enumName); - for (int j = 0; j < e.values.count(); ++j) - strreg(e.values.at(j)); + for (const QByteArray &val : e.values) + strreg(val); } } @@ -942,9 +902,9 @@ void Generator::generateEnums(int index) return; fprintf(out, "\n // enums: name, alias, flags, count, data\n"); - index += 5 * cdef->enumList.count(); + 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); int flags = 0; if (cdef->enumDeclarations.value(e.name)) @@ -955,16 +915,14 @@ void Generator::generateEnums(int index) stridx(e.name), e.enumName.isNull() ? stridx(e.name) : stridx(e.enumName), flags, - int(e.values.count()), + 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.enumName.isNull() ? e.name : e.enumName); @@ -1022,8 +980,6 @@ void Generator::generateMetacall() } if (cdef->propertyList.size()) { - - fprintf(out, "\n#ifndef QT_NO_PROPERTIES\n "); if (needElse) fprintf(out, "else "); fprintf(out, @@ -1031,8 +987,7 @@ void Generator::generateMetacall() " || _c == QMetaObject::ResetProperty || _c == QMetaObject::BindableProperty\n" " || _c == QMetaObject::RegisterPropertyMetaType) {\n" " qt_static_metacall(this, _c, _id, _a);\n" - " _id -= %d;\n }", int(cdef->propertyList.count())); - fprintf(out, "\n#endif // QT_NO_PROPERTIES"); + " _id -= %d;\n }", int(cdef->propertyList.size())); } if (methodList.size() || cdef->propertyList.size()) fprintf(out, "\n "); @@ -1040,10 +995,11 @@ void Generator::generateMetacall() } +// ### 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); @@ -1057,7 +1013,7 @@ 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); @@ -1074,33 +1030,46 @@ 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 || 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"); fprintf(out, " }"); needElse = true; isUsed_a = true; @@ -1142,16 +1111,17 @@ void Generator::generateStaticMetacall() if (f.isRawSlot) { fprintf(out, "QMethodRawArguments{ _a }"); } else { - 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, "(*reinterpret_cast< %s>(_a[%d]))",a.typeNameForCast.constData(), offset++); isUsed_a = true; } if (f.isPrivateSignal) { - if (argsCount > 0) + if (!f.arguments.isEmpty()) fprintf(out, ", "); fprintf(out, "%s", "QPrivateSignal()"); } @@ -1204,7 +1174,7 @@ void Generator::generateStaticMetacall() fprintf(out, " else if (_c == QMetaObject::IndexOfMethod) {\n"); fprintf(out, " int *result = reinterpret_cast<int *>(_a[0]);\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) continue; @@ -1212,15 +1182,16 @@ void Generator::generateStaticMetacall() fprintf(out, " {\n"); 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"); } @@ -1228,7 +1199,7 @@ void Generator::generateStaticMetacall() fprintf(out, ") const;\n"); else fprintf(out, ");\n"); - fprintf(out, " if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&%s::%s)) {\n", + fprintf(out, " if (_t _q_method = &%s::%s; *reinterpret_cast<_t *>(_a[1]) == _q_method) {\n", cdef->classname.constData(), f.name.constData()); fprintf(out, " *result = %d;\n", methodindex); fprintf(out, " return;\n"); @@ -1260,7 +1231,7 @@ void Generator::generateStaticMetacall() 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; } @@ -1271,8 +1242,7 @@ void Generator::generateStaticMetacall() bool needSet = false; bool needReset = false; bool hasBindableProperties = false; - for (int i = 0; i < cdef->propertyList.size(); ++i) { - const PropertyDef &p = cdef->propertyList.at(i); + 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 @@ -1282,10 +1252,8 @@ void Generator::generateStaticMetacall() 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"); auto setupMemberAccess = [this]() { @@ -1305,7 +1273,7 @@ void Generator::generateStaticMetacall() 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; @@ -1323,6 +1291,9 @@ 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()) fprintf(out, " case %d: *reinterpret_cast< %s*>(_v) = %s%s(); break;\n", propindex, p.type.constData(), prefix.constData(), p.read.constData()); @@ -1343,7 +1314,7 @@ void Generator::generateStaticMetacall() 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; @@ -1356,6 +1327,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()); @@ -1390,15 +1367,15 @@ void Generator::generateStaticMetacall() if (needReset) { 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"); @@ -1411,7 +1388,7 @@ void Generator::generateStaticMetacall() if (hasBindableProperties) { 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.bind.isEmpty()) continue; @@ -1428,7 +1405,6 @@ void Generator::generateStaticMetacall() fprintf(out, " }\n"); } fprintf(out, " }"); - fprintf(out, "\n#endif // QT_NO_PROPERTIES"); needElse = true; } @@ -1445,10 +1421,10 @@ void Generator::generateStaticMetacall() if (!isUsed_a) 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) return; @@ -1472,9 +1448,11 @@ 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) + 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); @@ -1505,7 +1483,7 @@ void Generator::generateSignal(FunctionDef *def,int index) } int i; for (i = 1; i < offset; ++i) - if (i <= def->arguments.count() && def->arguments.at(i - 1).type.isVolatile) + 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*>(std::addressof(_t%d)))", i); @@ -1564,8 +1542,7 @@ static CborError jsonValueToCbor(CborEncoder *parent, const QJsonValue &v) return cbor_encode_double(parent, d); } } - Q_UNREACHABLE(); - return CborUnknownError; + Q_UNREACHABLE_RETURN(CborUnknownError); } void Generator::generatePluginMetaData() @@ -1573,62 +1550,76 @@ void Generator::generatePluginMetaData() if (cdef->pluginData.iid.isEmpty()) return; - fprintf(out, "\nQT_PLUGIN_METADATA_SECTION\n" - "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()); + auto outputCborData = [this]() { + CborDevice dev(out); + CborEncoder enc; + cbor_encoder_init_writer(&enc, CborDevice::callback, &dev); + CborEncoder map; + cbor_encoder_create_map(&enc, &map, CborIndefiniteLength); - CborDevice dev(out); - CborEncoder enc; - cbor_encoder_init_writer(&enc, CborDevice::callback, &dev); - - CborEncoder map; - cbor_encoder_create_map(&enc, &map, CborIndefiniteLength); + dev.nextItem("\"IID\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID)); + cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size()); - dev.nextItem("\"IID\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::IID)); - cbor_encode_text_string(&map, cdef->pluginData.iid.constData(), cdef->pluginData.iid.size()); + dev.nextItem("\"className\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName)); + cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size()); - dev.nextItem("\"className\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::ClassName)); - cbor_encode_text_string(&map, cdef->classname.constData(), cdef->classname.size()); - - QJsonObject o = cdef->pluginData.metaData.object(); - if (!o.isEmpty()) { - dev.nextItem("\"MetaData\""); - cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData)); - jsonObjectToCbor(&map, o); - } + QJsonObject o = cdef->pluginData.metaData.object(); + if (!o.isEmpty()) { + dev.nextItem("\"MetaData\""); + cbor_encode_int(&map, int(QtPluginMetaDataKeys::MetaData)); + jsonObjectToCbor(&map, o); + } - 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()); - } + 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()); + } - // 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); - } + // 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); - fputs("\n};\n", out); + // 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") diff --git a/src/tools/moc/generator.h b/src/tools/moc/generator.h index 35128cb543..2d4d69ca05 100644 --- a/src/tools/moc/generator.h +++ b/src/tools/moc/generator.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 @@ -35,16 +10,19 @@ QT_BEGIN_NAMESPACE class Generator { + Moc *parser = nullptr; FILE *out; ClassDef *cdef; QList<uint> meta_data; public: - Generator(ClassDef *classDef, const QList<QByteArray> &metaTypes, + Generator(Moc *moc, ClassDef *classDef, const QList<QByteArray> &metaTypes, const QHash<QByteArray, QByteArray> &knownQObjectClasses, const QHash<QByteArray, QByteArray> &knownGadgets, FILE *outfile = nullptr, bool requireCompleteTypes = false); void generateCode(); + qsizetype registeredStringsCount() { return strings.size(); }; + private: bool registerableMetaType(const QByteArray &propertyType); void registerClassInfoStrings(); @@ -62,7 +40,7 @@ private: void generateProperties(); void generateMetacall(); void generateStaticMetacall(); - void generateSignal(FunctionDef *def, int index); + void generateSignal(const FunctionDef *def, int index); void generatePluginMetaData(); QMultiMap<QByteArray, int> automaticPropertyMetaTypesHelper(); QMap<int, QMultiMap<QByteArray, int>> diff --git a/src/tools/moc/keywords.cpp b/src/tools/moc/keywords.cpp index cc7d747f5b..6a1f58490f 100644 --- a/src/tools/moc/keywords.cpp +++ b/src/tools/moc/keywords.cpp @@ -1,41 +1,16 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 // auto generated // DO NOT EDIT. static const short keyword_trans[][128] = { - {0,0,0,0,0,0,0,0,0,579,576,0,0,0,0,0, + {0,0,0,0,0,0,0,0,0,618,615,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 579,252,577,580,8,38,239,578,25,26,236,234,30,235,27,237, + 618,252,616,619,8,38,239,617,25,26,236,234,30,235,27,237, 22,22,22,22,22,22,22,22,22,22,34,41,23,39,24,43, 0,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, - 8,21,8,8,8,8,8,8,8,8,8,31,582,32,238,8, + 8,21,8,8,8,8,8,8,8,8,8,31,621,32,238,8, 0,1,2,3,4,5,6,7,8,9,8,8,10,11,12,13, 14,8,15,16,17,18,19,20,8,8,8,36,245,37,248,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -116,7 +91,7 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,290,222,0,0,497,0,0,0, + 0,0,0,0,0,0,0,0,290,222,0,0,524,0,0,0, 0,0,0,0,55,0,0,330,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -155,7 +130,7 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,521,0,0,0,0,0,0,0,0,0,0,357, + 0,0,0,0,401,0,0,0,0,0,0,0,0,0,0,357, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -177,7 +152,7 @@ static const short keyword_trans[][128] = { {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,42,0,0,0,28,0, - 585,585,585,585,585,585,585,585,585,585,0,0,0,0,0,0, + 624,624,624,624,624,624,624,624,624,624,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -336,7 +311,7 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,583, + 0,0,0,0,0,0,0,0,0,0,623,0,0,0,0,622, 0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, @@ -372,29 +347,29 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,494,0,0,0,300,0,0,0,0,0,0,0,0,0,0, + 0,521,0,0,0,300,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,475,424,408,416,380,0,484,0,0,0,565,364,358, - 386,0,557,472,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,502,451,435,443,380,0,511,0,0,0,604,364,358, + 393,0,596,499,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,394,0,0,0, - 0,0,387,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,421,0,0,0, + 0,0,394,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,511,0,0,0,0,0,388, + 0,0,0,0,0,0,0,0,0,538,0,0,0,0,0,395, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, @@ -402,48 +377,64 @@ static const short keyword_trans[][128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,403,0,0,0,0,0,0,0,0,0,0,0,548,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,412,0,0,0,0,0,0,0,0,0,0,0,413, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,582,0,0,0,0,0,415, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,420,0,0,0,0,0,0,0,0,0,0,0,421, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,454,432,0,0,437,0,0,0,446,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,439,0,0,0,0,0,0,0,0,0,0,0,440, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,540,0,473,0,0,0,501,0,0,507,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,447,0,0,0,0,0,0,0,0,0,0,0,448, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,481,459,0,0,464,0,0,0,473,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,486,0,533,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,565,0,500,0,0,0,528,0,0,534,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 549,0,0,517,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,513,0,558,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 574,0,0,544,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} }; @@ -841,85 +832,85 @@ static const struct {CHARACTER, 0, 71, 383, CHARACTER}, {CHARACTER, 0, 69, 384, CHARACTER}, {CHARACTER, 0, 84, 385, CHARACTER}, - {Q_GADGET_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 44, 0, 0, CHARACTER}, - {CHARACTER, 45, 0, 0, CHARACTER}, + {Q_GADGET_TOKEN, 0, 95, 386, CHARACTER}, + {CHARACTER, 0, 69, 387, CHARACTER}, + {CHARACTER, 0, 88, 388, CHARACTER}, {CHARACTER, 0, 80, 389, CHARACTER}, - {CHARACTER, 0, 69, 390, CHARACTER}, + {CHARACTER, 0, 79, 390, CHARACTER}, {CHARACTER, 0, 82, 391, CHARACTER}, {CHARACTER, 0, 84, 392, CHARACTER}, - {CHARACTER, 0, 89, 393, CHARACTER}, + {Q_GADGET_EXPORT_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 44, 0, 0, CHARACTER}, + {CHARACTER, 45, 0, 0, CHARACTER}, + {CHARACTER, 0, 80, 396, CHARACTER}, + {CHARACTER, 0, 69, 397, CHARACTER}, + {CHARACTER, 0, 82, 398, CHARACTER}, + {CHARACTER, 0, 84, 399, CHARACTER}, + {CHARACTER, 0, 89, 400, CHARACTER}, {Q_PROPERTY_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 85, 395, CHARACTER}, - {CHARACTER, 0, 71, 396, CHARACTER}, - {CHARACTER, 0, 73, 397, CHARACTER}, - {CHARACTER, 0, 78, 398, CHARACTER}, - {CHARACTER, 0, 95, 399, CHARACTER}, - {CHARACTER, 0, 77, 400, CHARACTER}, - {CHARACTER, 0, 69, 401, CHARACTER}, - {CHARACTER, 0, 84, 402, CHARACTER}, - {CHARACTER, 0, 65, 403, CHARACTER}, - {CHARACTER, 0, 68, 404, CHARACTER}, - {CHARACTER, 0, 65, 405, CHARACTER}, - {CHARACTER, 0, 84, 406, CHARACTER}, - {CHARACTER, 0, 65, 407, CHARACTER}, - {Q_PLUGIN_METADATA_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 78, 409, CHARACTER}, + {CHARACTER, 0, 95, 402, CHARACTER}, + {CHARACTER, 46, 0, 0, CHARACTER}, + {CHARACTER, 0, 78, 404, CHARACTER}, + {CHARACTER, 0, 79, 405, CHARACTER}, + {CHARACTER, 0, 78, 406, CHARACTER}, + {CHARACTER, 0, 89, 407, CHARACTER}, + {CHARACTER, 0, 77, 408, CHARACTER}, + {CHARACTER, 0, 79, 409, CHARACTER}, {CHARACTER, 0, 85, 410, CHARACTER}, - {CHARACTER, 0, 77, 411, CHARACTER}, - {Q_ENUM_TOKEN, 46, 0, 0, CHARACTER}, + {CHARACTER, 0, 83, 411, CHARACTER}, + {CHARACTER, 0, 95, 412, CHARACTER}, + {CHARACTER, 0, 80, 413, CHARACTER}, + {CHARACTER, 0, 82, 414, CHARACTER}, + {CHARACTER, 47, 0, 0, CHARACTER}, + {CHARACTER, 0, 80, 416, CHARACTER}, + {CHARACTER, 0, 69, 417, CHARACTER}, + {CHARACTER, 0, 82, 418, CHARACTER}, + {CHARACTER, 0, 84, 419, CHARACTER}, + {CHARACTER, 0, 89, 420, CHARACTER}, + {QT_ANONYMOUS_PROPERTY_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 85, 422, CHARACTER}, + {CHARACTER, 0, 71, 423, CHARACTER}, + {CHARACTER, 0, 73, 424, CHARACTER}, + {CHARACTER, 0, 78, 425, CHARACTER}, + {CHARACTER, 0, 95, 426, CHARACTER}, + {CHARACTER, 0, 77, 427, CHARACTER}, + {CHARACTER, 0, 69, 428, CHARACTER}, + {CHARACTER, 0, 84, 429, CHARACTER}, + {CHARACTER, 0, 65, 430, CHARACTER}, + {CHARACTER, 0, 68, 431, CHARACTER}, + {CHARACTER, 0, 65, 432, CHARACTER}, + {CHARACTER, 0, 84, 433, CHARACTER}, + {CHARACTER, 0, 65, 434, CHARACTER}, + {Q_PLUGIN_METADATA_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 78, 436, CHARACTER}, + {CHARACTER, 0, 85, 437, CHARACTER}, + {CHARACTER, 0, 77, 438, CHARACTER}, + {Q_ENUM_TOKEN, 48, 0, 0, CHARACTER}, {Q_ENUMS_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 78, 414, CHARACTER}, - {CHARACTER, 0, 83, 415, CHARACTER}, + {CHARACTER, 0, 78, 441, CHARACTER}, + {CHARACTER, 0, 83, 442, CHARACTER}, {Q_ENUM_NS_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 76, 417, CHARACTER}, - {CHARACTER, 0, 65, 418, CHARACTER}, - {CHARACTER, 0, 71, 419, CHARACTER}, - {Q_FLAG_TOKEN, 47, 0, 0, CHARACTER}, + {CHARACTER, 0, 76, 444, CHARACTER}, + {CHARACTER, 0, 65, 445, CHARACTER}, + {CHARACTER, 0, 71, 446, CHARACTER}, + {Q_FLAG_TOKEN, 49, 0, 0, CHARACTER}, {Q_FLAGS_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 78, 422, CHARACTER}, - {CHARACTER, 0, 83, 423, CHARACTER}, + {CHARACTER, 0, 78, 449, CHARACTER}, + {CHARACTER, 0, 83, 450, CHARACTER}, {Q_FLAG_NS_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 69, 425, CHARACTER}, - {CHARACTER, 0, 67, 426, CHARACTER}, - {CHARACTER, 0, 76, 427, CHARACTER}, - {CHARACTER, 0, 65, 428, CHARACTER}, - {CHARACTER, 0, 82, 429, CHARACTER}, - {CHARACTER, 0, 69, 430, CHARACTER}, - {CHARACTER, 0, 95, 431, CHARACTER}, - {CHARACTER, 48, 0, 0, CHARACTER}, - {CHARACTER, 0, 76, 433, CHARACTER}, - {CHARACTER, 0, 65, 434, CHARACTER}, - {CHARACTER, 0, 71, 435, CHARACTER}, - {CHARACTER, 0, 83, 436, CHARACTER}, - {Q_DECLARE_FLAGS_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 78, 438, CHARACTER}, - {CHARACTER, 0, 84, 439, CHARACTER}, - {CHARACTER, 0, 69, 440, CHARACTER}, - {CHARACTER, 0, 82, 441, CHARACTER}, - {CHARACTER, 0, 70, 442, CHARACTER}, - {CHARACTER, 0, 65, 443, CHARACTER}, - {CHARACTER, 0, 67, 444, CHARACTER}, - {CHARACTER, 0, 69, 445, CHARACTER}, - {Q_DECLARE_INTERFACE_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 69, 447, CHARACTER}, - {CHARACTER, 0, 84, 448, CHARACTER}, - {CHARACTER, 0, 65, 449, CHARACTER}, - {CHARACTER, 0, 84, 450, CHARACTER}, - {CHARACTER, 0, 89, 451, CHARACTER}, - {CHARACTER, 0, 80, 452, CHARACTER}, - {CHARACTER, 0, 69, 453, CHARACTER}, - {Q_DECLARE_METATYPE_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 88, 455, CHARACTER}, - {CHARACTER, 0, 84, 456, CHARACTER}, + {CHARACTER, 0, 69, 452, CHARACTER}, + {CHARACTER, 0, 67, 453, CHARACTER}, + {CHARACTER, 0, 76, 454, CHARACTER}, + {CHARACTER, 0, 65, 455, CHARACTER}, + {CHARACTER, 0, 82, 456, CHARACTER}, {CHARACTER, 0, 69, 457, CHARACTER}, - {CHARACTER, 0, 78, 458, CHARACTER}, - {CHARACTER, 0, 83, 459, CHARACTER}, - {CHARACTER, 0, 73, 460, CHARACTER}, - {CHARACTER, 0, 79, 461, CHARACTER}, - {CHARACTER, 0, 78, 462, CHARACTER}, - {CHARACTER, 0, 95, 463, CHARACTER}, - {CHARACTER, 0, 73, 464, CHARACTER}, + {CHARACTER, 0, 95, 458, CHARACTER}, + {CHARACTER, 50, 0, 0, CHARACTER}, + {CHARACTER, 0, 76, 460, CHARACTER}, + {CHARACTER, 0, 65, 461, CHARACTER}, + {CHARACTER, 0, 71, 462, CHARACTER}, + {CHARACTER, 0, 83, 463, CHARACTER}, + {Q_DECLARE_FLAGS_TOKEN, 0, 0, 0, CHARACTER}, {CHARACTER, 0, 78, 465, CHARACTER}, {CHARACTER, 0, 84, 466, CHARACTER}, {CHARACTER, 0, 69, 467, CHARACTER}, @@ -927,116 +918,155 @@ static const struct {CHARACTER, 0, 70, 469, CHARACTER}, {CHARACTER, 0, 65, 470, CHARACTER}, {CHARACTER, 0, 67, 471, CHARACTER}, - {CHARACTER, 0, 69, 445, CHARACTER}, - {CHARACTER, 49, 0, 0, CHARACTER}, - {CHARACTER, 0, 84, 474, CHARACTER}, - {CHARACTER, 0, 83, 420, CHARACTER}, - {CHARACTER, 0, 76, 476, CHARACTER}, - {CHARACTER, 0, 65, 477, CHARACTER}, - {CHARACTER, 0, 83, 478, CHARACTER}, - {CHARACTER, 0, 83, 479, CHARACTER}, - {CHARACTER, 0, 73, 480, CHARACTER}, - {CHARACTER, 0, 78, 481, CHARACTER}, - {CHARACTER, 0, 70, 482, CHARACTER}, - {CHARACTER, 0, 79, 483, CHARACTER}, - {Q_CLASSINFO_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 472, CHARACTER}, + {Q_DECLARE_INTERFACE_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 474, CHARACTER}, + {CHARACTER, 0, 84, 475, CHARACTER}, + {CHARACTER, 0, 65, 476, CHARACTER}, + {CHARACTER, 0, 84, 477, CHARACTER}, + {CHARACTER, 0, 89, 478, CHARACTER}, + {CHARACTER, 0, 80, 479, CHARACTER}, + {CHARACTER, 0, 69, 480, CHARACTER}, + {Q_DECLARE_METATYPE_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 88, 482, CHARACTER}, + {CHARACTER, 0, 84, 483, CHARACTER}, + {CHARACTER, 0, 69, 484, CHARACTER}, {CHARACTER, 0, 78, 485, CHARACTER}, - {CHARACTER, 50, 0, 0, CHARACTER}, - {CHARACTER, 0, 69, 487, CHARACTER}, - {CHARACTER, 0, 82, 488, CHARACTER}, - {CHARACTER, 0, 70, 489, CHARACTER}, - {CHARACTER, 0, 65, 490, CHARACTER}, - {CHARACTER, 0, 67, 491, CHARACTER}, - {CHARACTER, 0, 69, 492, CHARACTER}, - {CHARACTER, 0, 83, 493, CHARACTER}, + {CHARACTER, 0, 83, 486, CHARACTER}, + {CHARACTER, 0, 73, 487, CHARACTER}, + {CHARACTER, 0, 79, 488, CHARACTER}, + {CHARACTER, 0, 78, 489, CHARACTER}, + {CHARACTER, 0, 95, 490, CHARACTER}, + {CHARACTER, 0, 73, 491, CHARACTER}, + {CHARACTER, 0, 78, 492, CHARACTER}, + {CHARACTER, 0, 84, 493, CHARACTER}, + {CHARACTER, 0, 69, 494, CHARACTER}, + {CHARACTER, 0, 82, 495, CHARACTER}, + {CHARACTER, 0, 70, 496, CHARACTER}, + {CHARACTER, 0, 65, 497, CHARACTER}, + {CHARACTER, 0, 67, 498, CHARACTER}, + {CHARACTER, 0, 69, 472, CHARACTER}, + {CHARACTER, 51, 0, 0, CHARACTER}, + {CHARACTER, 0, 84, 501, CHARACTER}, + {CHARACTER, 0, 83, 447, CHARACTER}, + {CHARACTER, 0, 76, 503, CHARACTER}, + {CHARACTER, 0, 65, 504, CHARACTER}, + {CHARACTER, 0, 83, 505, CHARACTER}, + {CHARACTER, 0, 83, 506, CHARACTER}, + {CHARACTER, 0, 73, 507, CHARACTER}, + {CHARACTER, 0, 78, 508, CHARACTER}, + {CHARACTER, 0, 70, 509, CHARACTER}, + {CHARACTER, 0, 79, 510, CHARACTER}, + {Q_CLASSINFO_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 78, 512, CHARACTER}, + {CHARACTER, 52, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 514, CHARACTER}, + {CHARACTER, 0, 82, 515, CHARACTER}, + {CHARACTER, 0, 70, 516, CHARACTER}, + {CHARACTER, 0, 65, 517, CHARACTER}, + {CHARACTER, 0, 67, 518, CHARACTER}, + {CHARACTER, 0, 69, 519, CHARACTER}, + {CHARACTER, 0, 83, 520, CHARACTER}, {Q_INTERFACES_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 108, 495, CHARACTER}, - {CHARACTER, 0, 115, 496, CHARACTER}, + {CHARACTER, 0, 108, 522, CHARACTER}, + {CHARACTER, 0, 115, 523, CHARACTER}, {SIGNALS, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 111, 498, CHARACTER}, - {CHARACTER, 0, 116, 499, CHARACTER}, - {CHARACTER, 0, 115, 500, CHARACTER}, + {CHARACTER, 0, 111, 525, CHARACTER}, + {CHARACTER, 0, 116, 526, CHARACTER}, + {CHARACTER, 0, 115, 527, CHARACTER}, {SLOTS, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 71, 502, CHARACTER}, - {CHARACTER, 0, 78, 503, CHARACTER}, - {CHARACTER, 0, 65, 504, CHARACTER}, - {CHARACTER, 0, 76, 505, CHARACTER}, - {Q_SIGNAL_TOKEN, 0, 83, 506, CHARACTER}, + {CHARACTER, 0, 71, 529, CHARACTER}, + {CHARACTER, 0, 78, 530, CHARACTER}, + {CHARACTER, 0, 65, 531, CHARACTER}, + {CHARACTER, 0, 76, 532, CHARACTER}, + {Q_SIGNAL_TOKEN, 0, 83, 533, CHARACTER}, {Q_SIGNALS_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 79, 508, CHARACTER}, - {CHARACTER, 0, 84, 509, CHARACTER}, - {Q_SLOT_TOKEN, 0, 83, 510, CHARACTER}, + {CHARACTER, 0, 79, 535, CHARACTER}, + {CHARACTER, 0, 84, 536, CHARACTER}, + {Q_SLOT_TOKEN, 0, 83, 537, CHARACTER}, {Q_SLOTS_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 86, 512, CHARACTER}, - {CHARACTER, 0, 65, 513, CHARACTER}, - {CHARACTER, 0, 84, 514, CHARACTER}, - {CHARACTER, 0, 69, 515, CHARACTER}, - {CHARACTER, 0, 95, 516, CHARACTER}, - {CHARACTER, 51, 0, 0, CHARACTER}, - {CHARACTER, 0, 76, 518, CHARACTER}, - {CHARACTER, 0, 79, 519, CHARACTER}, - {CHARACTER, 0, 84, 520, CHARACTER}, + {CHARACTER, 0, 86, 539, CHARACTER}, + {CHARACTER, 0, 65, 540, CHARACTER}, + {CHARACTER, 0, 84, 541, CHARACTER}, + {CHARACTER, 0, 69, 542, CHARACTER}, + {CHARACTER, 0, 95, 543, CHARACTER}, + {CHARACTER, 53, 0, 0, CHARACTER}, + {CHARACTER, 0, 76, 545, CHARACTER}, + {CHARACTER, 0, 79, 546, CHARACTER}, + {CHARACTER, 0, 84, 547, CHARACTER}, {Q_PRIVATE_SLOT_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 95, 522, CHARACTER}, - {CHARACTER, 0, 77, 523, CHARACTER}, - {CHARACTER, 0, 79, 524, CHARACTER}, - {CHARACTER, 0, 67, 525, CHARACTER}, - {CHARACTER, 0, 95, 526, CHARACTER}, - {CHARACTER, 0, 67, 527, CHARACTER}, - {CHARACTER, 0, 79, 528, CHARACTER}, - {CHARACTER, 0, 77, 529, CHARACTER}, - {CHARACTER, 0, 80, 530, CHARACTER}, - {CHARACTER, 0, 65, 531, CHARACTER}, - {CHARACTER, 0, 84, 532, CHARACTER}, + {CHARACTER, 0, 79, 549, CHARACTER}, + {CHARACTER, 0, 67, 550, CHARACTER}, + {CHARACTER, 0, 95, 551, CHARACTER}, + {CHARACTER, 0, 67, 552, CHARACTER}, + {CHARACTER, 0, 79, 553, CHARACTER}, + {CHARACTER, 0, 77, 554, CHARACTER}, + {CHARACTER, 0, 80, 555, CHARACTER}, + {CHARACTER, 0, 65, 556, CHARACTER}, + {CHARACTER, 0, 84, 557, CHARACTER}, {Q_MOC_COMPAT_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 79, 534, CHARACTER}, - {CHARACTER, 0, 75, 535, CHARACTER}, - {CHARACTER, 0, 65, 536, CHARACTER}, - {CHARACTER, 0, 66, 537, CHARACTER}, - {CHARACTER, 0, 76, 538, CHARACTER}, - {CHARACTER, 0, 69, 539, CHARACTER}, + {CHARACTER, 0, 79, 559, CHARACTER}, + {CHARACTER, 0, 75, 560, CHARACTER}, + {CHARACTER, 0, 65, 561, CHARACTER}, + {CHARACTER, 0, 66, 562, CHARACTER}, + {CHARACTER, 0, 76, 563, CHARACTER}, + {CHARACTER, 0, 69, 564, CHARACTER}, {Q_INVOKABLE_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 82, 541, CHARACTER}, - {CHARACTER, 0, 73, 542, CHARACTER}, - {CHARACTER, 0, 80, 543, CHARACTER}, - {CHARACTER, 0, 84, 544, CHARACTER}, - {CHARACTER, 0, 65, 545, CHARACTER}, - {CHARACTER, 0, 66, 546, CHARACTER}, - {CHARACTER, 0, 76, 547, CHARACTER}, - {CHARACTER, 0, 69, 548, CHARACTER}, + {CHARACTER, 0, 82, 566, CHARACTER}, + {CHARACTER, 0, 73, 567, CHARACTER}, + {CHARACTER, 0, 80, 568, CHARACTER}, + {CHARACTER, 0, 84, 569, CHARACTER}, + {CHARACTER, 0, 65, 570, CHARACTER}, + {CHARACTER, 0, 66, 571, CHARACTER}, + {CHARACTER, 0, 76, 572, CHARACTER}, + {CHARACTER, 0, 69, 573, CHARACTER}, {Q_SCRIPTABLE_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 82, 550, CHARACTER}, - {CHARACTER, 0, 79, 551, CHARACTER}, - {CHARACTER, 0, 80, 552, CHARACTER}, - {CHARACTER, 0, 69, 553, CHARACTER}, - {CHARACTER, 0, 82, 554, CHARACTER}, - {CHARACTER, 0, 84, 555, CHARACTER}, - {CHARACTER, 0, 89, 556, CHARACTER}, + {CHARACTER, 0, 82, 575, CHARACTER}, + {CHARACTER, 0, 79, 576, CHARACTER}, + {CHARACTER, 0, 80, 577, CHARACTER}, + {CHARACTER, 0, 69, 578, CHARACTER}, + {CHARACTER, 0, 82, 579, CHARACTER}, + {CHARACTER, 0, 84, 580, CHARACTER}, + {CHARACTER, 0, 89, 581, CHARACTER}, {Q_PRIVATE_PROPERTY_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 69, 558, CHARACTER}, - {CHARACTER, 0, 86, 559, CHARACTER}, - {CHARACTER, 0, 73, 560, CHARACTER}, - {CHARACTER, 0, 83, 561, CHARACTER}, - {CHARACTER, 0, 73, 562, CHARACTER}, - {CHARACTER, 0, 79, 563, CHARACTER}, - {CHARACTER, 0, 78, 564, CHARACTER}, + {CHARACTER, 0, 86, 583, CHARACTER}, + {CHARACTER, 0, 65, 584, CHARACTER}, + {CHARACTER, 0, 84, 585, CHARACTER}, + {CHARACTER, 0, 69, 586, CHARACTER}, + {CHARACTER, 0, 95, 587, CHARACTER}, + {CHARACTER, 0, 80, 588, CHARACTER}, + {CHARACTER, 0, 82, 589, CHARACTER}, + {CHARACTER, 0, 79, 590, CHARACTER}, + {CHARACTER, 0, 80, 591, CHARACTER}, + {CHARACTER, 0, 69, 592, CHARACTER}, + {CHARACTER, 0, 82, 593, CHARACTER}, + {CHARACTER, 0, 84, 594, CHARACTER}, + {CHARACTER, 0, 89, 595, CHARACTER}, + {QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN, 0, 0, 0, CHARACTER}, + {CHARACTER, 0, 69, 597, CHARACTER}, + {CHARACTER, 0, 86, 598, CHARACTER}, + {CHARACTER, 0, 73, 599, CHARACTER}, + {CHARACTER, 0, 83, 600, CHARACTER}, + {CHARACTER, 0, 73, 601, CHARACTER}, + {CHARACTER, 0, 79, 602, CHARACTER}, + {CHARACTER, 0, 78, 603, CHARACTER}, {Q_REVISION_TOKEN, 0, 0, 0, CHARACTER}, - {CHARACTER, 0, 79, 566, CHARACTER}, - {CHARACTER, 0, 67, 567, CHARACTER}, - {CHARACTER, 0, 95, 568, CHARACTER}, - {CHARACTER, 0, 73, 569, CHARACTER}, - {CHARACTER, 0, 78, 570, CHARACTER}, - {CHARACTER, 0, 67, 571, CHARACTER}, - {CHARACTER, 0, 76, 572, CHARACTER}, - {CHARACTER, 0, 85, 573, CHARACTER}, - {CHARACTER, 0, 68, 574, CHARACTER}, - {CHARACTER, 0, 69, 575, CHARACTER}, + {CHARACTER, 0, 79, 605, CHARACTER}, + {CHARACTER, 0, 67, 606, CHARACTER}, + {CHARACTER, 0, 95, 607, CHARACTER}, + {CHARACTER, 0, 73, 608, CHARACTER}, + {CHARACTER, 0, 78, 609, CHARACTER}, + {CHARACTER, 0, 67, 610, CHARACTER}, + {CHARACTER, 0, 76, 611, CHARACTER}, + {CHARACTER, 0, 85, 612, CHARACTER}, + {CHARACTER, 0, 68, 613, CHARACTER}, + {CHARACTER, 0, 69, 614, CHARACTER}, {Q_MOC_INCLUDE_TOKEN, 0, 0, 0, CHARACTER}, {NEWLINE, 0, 0, 0, NOTOKEN}, {QUOTE, 0, 0, 0, NOTOKEN}, {SINGLEQUOTE, 0, 0, 0, NOTOKEN}, {WHITESPACE, 0, 0, 0, NOTOKEN}, - {HASH, 0, 35, 581, HASH}, + {HASH, 0, 35, 620, HASH}, {PP_HASHHASH, 0, 0, 0, NOTOKEN}, {BACKSLASH, 0, 0, 0, NOTOKEN}, {CPP_COMMENT, 0, 0, 0, NOTOKEN}, diff --git a/src/tools/moc/main.cpp b/src/tools/moc/main.cpp index 3e98fbf2b8..bb51352519 100644 --- a/src/tools/moc/main.cpp +++ b/src/tools/moc/main.cpp @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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. +// Copyright (C) 2016 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include <depfile_shared.h> #include "preprocessor.h" @@ -48,6 +23,8 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + /* This function looks at two file names and returns the name of the infile with a path relative to outfile. @@ -153,7 +130,7 @@ static QStringList argumentsFromCommandLineAndFile(const QStringList &arguments, allArguments.reserve(arguments.size()); for (const QString &argument : arguments) { // "@file" doesn't start with a '-' so we can't use QCommandLineParser for it - if (argument.startsWith(QLatin1Char('@'))) { + if (argument.startsWith(u'@')) { QString optionsFile = argument; optionsFile.remove(0, 1); if (optionsFile.isEmpty()) { @@ -306,6 +283,10 @@ int runMoc(int argc, char **argv) jsonOption.setDescription(QStringLiteral("In addition to generating C++ code, create a machine-readable JSON file in a file that matches the output file and an extra .json extension.")); parser.addOption(jsonOption); + QCommandLineOption debugIncludesOption(QStringLiteral("debug-includes")); + debugIncludesOption.setDescription(QStringLiteral("Display debug messages of each considered include path.")); + parser.addOption(debugIncludesOption); + QCommandLineOption collectOption(QStringLiteral("collect-json")); collectOption.setDescription(QStringLiteral("Instead of processing C++ code, collect previously generated JSON output into a single file.")); parser.addOption(collectOption); @@ -349,8 +330,8 @@ int runMoc(int argc, char **argv) if (parser.isSet(collectOption)) return collectJson(files, output, hasOptionFiles); - if (files.count() > 1) { - error(qPrintable(QLatin1String("Too many input files specified: '") + files.join(QLatin1String("' '")) + QLatin1Char('\''))); + if (files.size() > 1) { + error(qPrintable("Too many input files specified: '"_L1 + files.join("' '"_L1) + u'\'')); parser.showHelp(1); } else if (!files.isEmpty()) { filename = files.first(); @@ -358,6 +339,7 @@ int runMoc(int argc, char **argv) const bool ignoreConflictingOptions = parser.isSet(ignoreConflictsOption); pp.preprocessOnly = parser.isSet(preprocessOption); + pp.setDebugIncludes(parser.isSet(debugIncludesOption)); if (parser.isSet(noIncludeOption)) { moc.noInclude = true; autoInclude = false; @@ -385,7 +367,7 @@ int runMoc(int argc, char **argv) for (const QString &path : includePaths) pp.includes += Preprocessor::IncludePath(QFile::encodeName(path)); QString compilerFlavor = parser.value(compilerFlavorOption); - if (compilerFlavor.isEmpty() || compilerFlavor == QLatin1String("unix")) { + if (compilerFlavor.isEmpty() || compilerFlavor == "unix"_L1) { // traditional Unix compilers use both CPATH and CPLUS_INCLUDE_PATH // $CPATH feeds to #include <...> and #include "...", whereas // CPLUS_INCLUDE_PATH is equivalent to GCC's -isystem, so we parse later @@ -395,14 +377,14 @@ int runMoc(int argc, char **argv) const auto cplus_include_path = qgetenv("CPLUS_INCLUDE_PATH").split(QDir::listSeparator().toLatin1()); for (const QByteArray &p : cplus_include_path) pp.includes += Preprocessor::IncludePath(p); - } else if (compilerFlavor == QLatin1String("msvc")) { + } else if (compilerFlavor == "msvc"_L1) { // MSVC uses one environment variable: INCLUDE const auto include = qgetenv("INCLUDE").split(QDir::listSeparator().toLatin1()); for (const QByteArray &p : include) pp.includes += Preprocessor::IncludePath(p); } else { - error(qPrintable(QLatin1String("Unknown compiler flavor '") + compilerFlavor + - QLatin1String("'; valid values are: msvc, unix."))); + error(qPrintable("Unknown compiler flavor '"_L1 + compilerFlavor + + "'; valid values are: msvc, unix."_L1)); parser.showHelp(1); } @@ -417,7 +399,7 @@ int runMoc(int argc, char **argv) for (const QString &arg : defines) { QByteArray name = arg.toLocal8Bit(); QByteArray value("1"); - int eq = name.indexOf('='); + const qsizetype eq = name.indexOf('='); if (eq >= 0) { value = name.mid(eq + 1); name = name.left(eq); @@ -441,16 +423,16 @@ int runMoc(int argc, char **argv) pp.macros.remove(macro); } const QStringList noNotesCompatValues = parser.values(noNotesWarningsCompatOption); - if (parser.isSet(noNotesOption) || noNotesCompatValues.contains(QLatin1String("n"))) + if (parser.isSet(noNotesOption) || noNotesCompatValues.contains("n"_L1)) moc.displayNotes = false; - if (parser.isSet(noWarningsOption) || noNotesCompatValues.contains(QLatin1String("w"))) + if (parser.isSet(noWarningsOption) || noNotesCompatValues.contains("w"_L1)) moc.displayWarnings = moc.displayNotes = false; if (autoInclude) { - int spos = filename.lastIndexOf(QDir::separator()); - int ppos = filename.lastIndexOf(QLatin1Char('.')); + qsizetype spos = filename.lastIndexOf(QDir::separator()); + qsizetype ppos = filename.lastIndexOf(u'.'); // spos >= -1 && ppos > spos => ppos >= 0 - moc.noInclude = (ppos > spos && filename.at(ppos + 1).toLower() != QLatin1Char('h')); + moc.noInclude = (ppos > spos && filename.at(ppos + 1).toLower() != u'h'); } if (defaultInclude) { if (moc.includePath.isEmpty()) { @@ -467,11 +449,14 @@ int runMoc(int argc, char **argv) if (filename.isEmpty()) { filename = QStringLiteral("standard input"); - in.open(stdin, QIODevice::ReadOnly); + if (!in.open(stdin, QIODevice::ReadOnly)) { + fprintf(stderr, "moc: cannot open standard input: %s\n", qPrintable(in.errorString())); + return 1; + } } else { in.setFileName(filename); if (!in.open(QIODevice::ReadOnly)) { - fprintf(stderr, "moc: %s: No such file\n", qPrintable(filename)); + fprintf(stderr, "moc: cannot open %s: %s\n", qPrintable(filename), qPrintable(in.errorString())); return 1; } moc.filename = filename.toLocal8Bit(); @@ -479,13 +464,13 @@ int runMoc(int argc, char **argv) const auto metadata = parser.values(metadataOption); for (const QString &md : metadata) { - int split = md.indexOf(QLatin1Char('=')); + qsizetype split = md.indexOf(u'='); QString key = md.left(split); QString value = md.mid(split + 1); if (split == -1 || key.isEmpty() || value.isEmpty()) { error("missing key or value for option '-M'"); - } else if (key.indexOf(QLatin1Char('.')) != -1) { + } else if (key.indexOf(u'.') != -1) { // Don't allow keys with '.' for now, since we might need this // format later for more advanced meta data API error("A key cannot contain the letter '.' for option '-M'"); @@ -499,6 +484,17 @@ int runMoc(int argc, char **argv) moc.currentFilenames.push(filename.toLocal8Bit()); moc.includes = pp.includes; + if (Q_UNLIKELY(parser.isSet(debugIncludesOption))) { + fprintf(stderr, "debug-includes: include search list:\n"); + + for (auto &includePath : pp.includes) { + fprintf(stderr, "debug-includes: '%s' framework: %d \n", + includePath.path.constData(), + includePath.isFrameworkPath); + } + fprintf(stderr, "debug-includes: end of search list.\n"); + } + // 1. preprocess const auto includeFiles = parser.values(includeOption); QStringList validIncludesFiles; @@ -543,12 +539,15 @@ int runMoc(int argc, char **argv) if (!out) #endif { - fprintf(stderr, "moc: Cannot create %s\n", QFile::encodeName(output).constData()); + const auto fopen_errno = errno; + fprintf(stderr, "moc: Cannot create %s. Error: %s\n", + QFile::encodeName(output).constData(), + strerror(fopen_errno)); return 1; } if (parser.isSet(jsonOption)) { - const QString jsonOutputFileName = output + QLatin1String(".json"); + const QString jsonOutputFileName = output + ".json"_L1; FILE *f; #if defined(_MSC_VER) if (_wfopen_s(&f, reinterpret_cast<const wchar_t *>(jsonOutputFileName.utf16()), L"w") != 0) @@ -556,9 +555,12 @@ int runMoc(int argc, char **argv) f = fopen(QFile::encodeName(jsonOutputFileName).constData(), "w"); if (!f) #endif - fprintf(stderr, "moc: Cannot create JSON output file %s. %s\n", + { + const auto fopen_errno = errno; + fprintf(stderr, "moc: Cannot create JSON output file %s. Error: %s\n", QFile::encodeName(jsonOutputFileName).constData(), - strerror(errno)); + strerror(fopen_errno)); + } jsonOutput.reset(f); } } else { // use stdout @@ -589,7 +591,7 @@ int runMoc(int argc, char **argv) if (parser.isSet(depFilePathOption)) { depOutputFileName = parser.value(depFilePathOption); } else if (outputToFile) { - depOutputFileName = output + QLatin1String(".d"); + depOutputFileName = output + ".d"_L1; } else { fprintf(stderr, "moc: Writing to stdout, but no depfile path specified.\n"); } @@ -603,9 +605,12 @@ int runMoc(int argc, char **argv) depFileHandleRaw = fopen(QFile::encodeName(depOutputFileName).constData(), "w"); if (!depFileHandleRaw) #endif - fprintf(stderr, "moc: Cannot create dep output file '%s'. %s\n", + { + const auto fopen_errno = errno; + fprintf(stderr, "moc: Cannot create dep output file '%s'. Error: %s\n", QFile::encodeName(depOutputFileName).constData(), - strerror(errno)); + strerror(fopen_errno)); + } depFileHandle.reset(depFileHandleRaw); if (!depFileHandle.isNull()) { diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 56440129c2..3cbe331f14 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2020 The Qt Company Ltd. -** Copyright (C) 2019 Olivier Goffart <ogoffart@woboq.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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) 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" @@ -43,12 +18,23 @@ QT_BEGIN_NAMESPACE +using namespace Qt::StringLiterals; + // 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 @@ -63,6 +49,9 @@ bool Moc::parseClassHead(ClassDef *def) return false; } while (token); + // support attributes like "class [[deprecated]]] name" + skipCxxAttributes(); + if (!test(IDENTIFIER)) // typedef struct { ... } return false; QByteArray name = lexem(); @@ -107,17 +96,17 @@ bool Moc::parseClassHead(ClassDef *def) else test(PUBLIC); test(VIRTUAL); - const QByteArray type = parseType().name; + const Type type = parseType(); // ignore the 'class Foo : BAR(Baz)' case if (test(LPAREN)) { until(RPAREN); } else { - def->superclassList += qMakePair(type, access); + def->superclassList.push_back({type.name, toFullyQualified(type.name), access}); } } while (test(COMMA)); if (!def->superclassList.isEmpty() - && knownGadgets.contains(def->superclassList.constFirst().first)) { + && 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); @@ -263,7 +252,7 @@ bool Moc::parseEnum(EnumDef *def) } if (test(COLON)) { // C++11 strongly typed enum // enum Foo : unsigned long { ... }; - parseType(); //ignore the result + def->type = normalizeType(parseType().name); } if (!test(LBRACE)) return false; @@ -320,7 +309,7 @@ void Moc::parseFunctionArguments(FunctionDef *def) arg.rightType += lexem(); } arg.normalizedType = normalizeType(QByteArray(arg.type.name + ' ' + arg.rightType)); - arg.typeNameForCast = normalizeType(QByteArray(noRef(arg.type.name) + "(*)" + arg.rightType)); + arg.typeNameForCast = QByteArray("std::add_pointer_t<"+arg.normalizedType+">"); if (test(EQ)) arg.isDefault = true; def->arguments += arg; @@ -338,6 +327,9 @@ void Moc::parseFunctionArguments(FunctionDef *def) 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) @@ -388,7 +380,7 @@ QTypeRevision Moc::parseRevision() revisionString.remove(0, 1); revisionString.chop(1); const QList<QByteArray> majorMinor = revisionString.split(','); - switch (majorMinor.length()) { + switch (majorMinor.size()) { case 1: { bool ok = false; const int revision = revisionString.toInt(&ok); @@ -429,8 +421,7 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro) def->isVirtual = false; def->isStatic = false; //skip modifiers and attributes - while (test(INLINE) || (test(STATIC) && (def->isStatic = true) == true) || - (test(VIRTUAL) && (def->isVirtual = true) == true) //mark as virtual + while (testForFunctionModifiers(def) || skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {} bool templateFunction = (lookup() == TEMPLATE); def->type = parseType(); @@ -441,31 +432,29 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro) error(); } bool scopedFunctionName = false; - if (test(LPAREN)) { - def->name = def->type.name; - scopedFunctionName = def->type.isScoped; - def->type = Type("int"); - } else { - 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(); + // 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; } - next(LPAREN, "Not a signal or slot declaration"); - def->name = tempType.name; - scopedFunctionName = tempType.isScoped; + 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); @@ -529,14 +518,20 @@ bool Moc::parseFunction(FunctionDef *def, bool inMacro) 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 (test(EXPLICIT) || test(INLINE) || (test(STATIC) && (def->isStatic = true) == true) || - (test(VIRTUAL) && (def->isVirtual = true) == true) //mark as virtual + while (testForFunctionModifiers(def) || skipCxxAttributes() || testFunctionAttribute(def) || testFunctionRevision(def)) {} bool tilde = test(TILDE); def->type = parseType(); @@ -551,10 +546,15 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) def->isConstructor = !tilde; def->type = Type(); } else { - def->type = Type("int"); + // missing type name? => Skip + return false; } } else { - Type tempType = parseType();; + // ### 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 @@ -601,6 +601,63 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def) 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() { @@ -610,11 +667,17 @@ void Moc::parse() Token t = next(); switch (t) { case NAMESPACE: { - int rewind = index; + 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(); @@ -636,11 +699,8 @@ void Moc::parse() def.end = index; index = def.begin + 1; - for (int i = namespaceList.size() - 1; i >= 0; --i) { - if (inNamespace(&namespaceList.at(i))) { - def.qualified.prepend(namespaceList.at(i).classname + "::"); - } - } + prependNamespaces(def, namespaceList); + for (const QByteArray &ns : nested) { NamespaceDef parentNs; parentNs.classname = ns; @@ -655,8 +715,10 @@ void Moc::parse() switch (next()) { case NAMESPACE: if (test(IDENTIFIER)) { - while (test(SCOPE)) + while (test(SCOPE)) { + test(INLINE); // ignore inline namespaces next(IDENTIFIER); + } if (test(EQ)) { // namespace Foo = Bar::Baz; until(SEMIC); @@ -770,6 +832,12 @@ void Moc::parse() 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; @@ -780,9 +848,7 @@ void Moc::parse() if (!def.hasQObject && !def.hasQGadget) continue; - for (int i = namespaceList.size() - 1; i >= 0; --i) - if (inNamespace(&namespaceList.at(i))) - def.qualified.prepend(namespaceList.at(i).classname + "::"); + prependNamespaces(def, namespaceList); QHash<QByteArray, QByteArray> &classHash = def.hasQObject ? knownQObjectClasses : knownGadgets; classHash.insert(def.classname, def.qualified); @@ -795,10 +861,9 @@ void Moc::parse() continue; ClassDef def; if (parseClassHead(&def)) { + prependNamespaces(def, namespaceList); + FunctionDef::Access access = FunctionDef::Private; - for (int i = namespaceList.size() - 1; i >= 0; --i) - if (inNamespace(&namespaceList.at(i))) - def.qualified.prepend(namespaceList.at(i).classname + "::"); while (inClass(&def) && hasNext()) { switch ((t = next())) { case PRIVATE: @@ -847,13 +912,22 @@ void Moc::parse() 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); + parseProperty(&def, Named); + break; + case QT_ANONYMOUS_PROPERTY_TOKEN: + parseProperty(&def, Anonymous); break; case Q_PLUGIN_METADATA_TOKEN: parsePluginData(&def); @@ -888,7 +962,10 @@ void Moc::parse() parseSlotInPrivate(&def, access); break; case Q_PRIVATE_PROPERTY_TOKEN: - parsePrivateProperty(&def); + parsePrivateProperty(&def, Named); + break; + case QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN: + parsePrivateProperty(&def, Anonymous); break; case ENUM: { EnumDef enumDef; @@ -901,16 +978,12 @@ void Moc::parse() default: FunctionDef funcDef; funcDef.access = access; - int rewind = index--; + qsizetype rewind = index--; if (parseMaybeFunction(&def, &funcDef)) { if (funcDef.isConstructor) { if ((access == FunctionDef::Public) && funcDef.isInvokable) { def.constructorList += funcDef; - while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) { - funcDef.wasCloned = true; - funcDef.arguments.removeLast(); - def.constructorList += funcDef; - } + handleDefaultArguments(&def.constructorList, funcDef); } } else if (funcDef.isDestructor) { // don't care about destructors @@ -919,29 +992,17 @@ void Moc::parse() def.publicList += funcDef; if (funcDef.isSlot) { def.slotList += funcDef; - while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) { - funcDef.wasCloned = true; - funcDef.arguments.removeLast(); - def.slotList += funcDef; - } + handleDefaultArguments(&def.slotList, funcDef); if (funcDef.revision > 0) ++def.revisionedMethods; } else if (funcDef.isSignal) { def.signalList += funcDef; - while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) { - funcDef.wasCloned = true; - funcDef.arguments.removeLast(); - def.signalList += funcDef; - } + handleDefaultArguments(&def.signalList, funcDef); if (funcDef.revision > 0) ++def.revisionedMethods; } else if (funcDef.isInvokable) { def.methodList += funcDef; - while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) { - funcDef.wasCloned = true; - funcDef.arguments.removeLast(); - def.methodList += funcDef; - } + handleDefaultArguments(&def.methodList, funcDef); if (funcDef.revision > 0) ++def.revisionedMethods; } @@ -966,16 +1027,20 @@ void Moc::parse() if (!def.pluginData.iid.isEmpty()) def.pluginData.metaArgs = metaArgs; - checkSuperClasses(&def); + 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 : qAsConst(namespaceList)) { + for (const auto &n : std::as_const(namespaceList)) { if (!n.hasQNamespace) continue; ClassDef def; @@ -988,8 +1053,10 @@ void Moc::parse() 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); @@ -1067,25 +1134,27 @@ static QByteArrayList requiredQtContainers(const QList<ClassDef> &classes) void Moc::generate(FILE *out, FILE *jsonOutput) { - QByteArray fn = filename; - int i = filename.length()-1; - while (i > 0 && filename.at(i - 1) != '/' && filename.at(i - 1) != '\\') - --i; // skip path - if (i >= 0) - fn = filename.mid(i); + 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"); - fprintf(out, "#include <memory>\n"); // For std::addressof + // 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 (int i = 0; i < includeFiles.size(); ++i) { - QByteArray inc = includeFiles.at(i); - if (inc.at(0) != '<' && inc.at(0) != '"') { + 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 + '\"'; @@ -1096,7 +1165,6 @@ void Moc::generate(FILE *out, FILE *jsonOutput) if (classList.size() && classList.constFirst().classname == "Qt") fprintf(out, "#include <QtCore/qobject.h>\n"); - fprintf(out, "#include <QtCore/qbytearray.h>\n"); // For QByteArrayData fprintf(out, "#include <QtCore/qmetatype.h>\n"); // For QMetaType::Type if (mustIncludeQPluginH) fprintf(out, "#include <QtCore/qplugin.h>\n"); @@ -1105,6 +1173,10 @@ void Moc::generate(FILE *out, FILE *jsonOutput) 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()); @@ -1115,32 +1187,44 @@ void Moc::generate(FILE *out, FILE *jsonOutput) " much.)\"\n", QT_VERSION_STR); fprintf(out, "#endif\n\n"); - fprintf(out, "QT_BEGIN_MOC_NAMESPACE\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 (i = 0; i < classList.size(); ++i) { - Generator generator(&classList[i], metaTypes, knownQObjectClasses, knownGadgets, out, requireCompleteTypes); + 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"); - fprintf(out, "QT_END_MOC_NAMESPACE\n"); if (jsonOutput) { QJsonObject mocData; - mocData[QLatin1String("outputRevision")] = mocOutputRevision; - mocData[QLatin1String("inputFile")] = QLatin1String(fn.constData()); + mocData["outputRevision"_L1] = mocOutputRevision; + mocData["inputFile"_L1] = QLatin1StringView(fn.constData()); QJsonArray classesJsonFormatted; - for (const ClassDef &cdef: qAsConst(classList)) + for (const ClassDef &cdef: std::as_const(classList)) classesJsonFormatted.append(cdef.toJson()); if (!classesJsonFormatted.isEmpty()) - mocData[QLatin1String("classes")] = classesJsonFormatted; + mocData["classes"_L1] = classesJsonFormatted; QJsonDocument jsonDoc(mocData); fputs(jsonDoc.toJson().constData(), jsonOutput); @@ -1185,11 +1269,7 @@ void Moc::parseSlots(ClassDef *def, FunctionDef::Access access) ++def->revisionedMethods; } def->slotList += funcDef; - while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) { - funcDef.wasCloned = true; - funcDef.arguments.removeLast(); - def->slotList += funcDef; - } + handleDefaultArguments(&def->slotList, funcDef); } } @@ -1233,15 +1313,11 @@ void Moc::parseSignals(ClassDef *def) ++def->revisionedMethods; } def->signalList += funcDef; - while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) { - funcDef.wasCloned = true; - funcDef.arguments.removeLast(); - def->signalList += funcDef; - } + handleDefaultArguments(&def->signalList, funcDef); } } -void Moc::createPropertyDef(PropertyDef &propDef, int propertyIndex) +void Moc::createPropertyDef(PropertyDef &propDef, int propertyIndex, Moc::PropertyMode mode) { propDef.location = index; propDef.relativeIndex = propertyIndex; @@ -1271,8 +1347,10 @@ void Moc::createPropertyDef(PropertyDef &propDef, int propertyIndex) propDef.type = type; - next(); - propDef.name = lexem(); + if (mode == Moc::Named) { + next(); + propDef.name = lexem(); + } parsePropertyAttributes(propDef); } @@ -1289,7 +1367,8 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef) }; while (test(IDENTIFIER)) { - const QByteArray l = lexem(); + const Symbol &lsym = symbol(); + const QByteArray l = lsym.lexem(); if (l[0] == 'C' && l == "CONSTANT") { propDef.constant = true; continue; @@ -1312,11 +1391,15 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef) QByteArray v, v2; if (test(LPAREN)) { v = lexemUntil(RPAREN); - v = v.mid(1, v.length() - 2); // removes the '(' and ')' + v = v.mid(1, v.size() - 2); // removes the '(' and ')' } else if (test(INTEGER_LITERAL)) { v = lexem(); if (l != "REVISION") - error(1); + error(lsym); + } else if (test(DEFAULT)) { + v = lexem(); + if (l != "READ" && l != "WRITE") + error(lsym); } else { next(IDENTIFIER); v = lexem(); @@ -1330,21 +1413,21 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef) if (l == "MEMBER") propDef.member = v; else - error(2); + error(lsym); break; case 'R': if (l == "READ") propDef.read = v; else if (l == "RESET") - propDef.reset = v + v2; + propDef.reset = v; else if (l == "REVISION") { bool ok = false; const int minor = v.toInt(&ok); if (!ok || !QTypeRevision::isValidSegment(minor)) - error(1); + error(lsym); propDef.revision = QTypeRevision::fromMinorVersion(minor).toEncodedVersion<int>(); } else - error(2); + error(lsym); break; case 'S': if (l == "SCRIPTABLE") { @@ -1354,27 +1437,27 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef) propDef.stored = v + v2; checkIsFunction(propDef.stored, "STORED"); } else - error(2); + error(lsym); break; - case 'W': if (l != "WRITE") error(2); + case 'W': if (l != "WRITE") error(lsym); propDef.write = v; break; - case 'B': if (l != "BINDABLE") error(2); + case 'B': if (l != "BINDABLE") error(lsym); propDef.bind = v; break; - case 'D': if (l != "DESIGNABLE") error(2); + case 'D': if (l != "DESIGNABLE") error(lsym); propDef.designable = v + v2; checkIsFunction(propDef.designable, "DESIGNABLE"); break; - case 'N': if (l != "NOTIFY") error(2); + case 'N': if (l != "NOTIFY") error(lsym); propDef.notify = v; break; - case 'U': if (l != "USER") error(2); + case 'U': if (l != "USER") error(lsym); propDef.user = v + v2; checkIsFunction(propDef.user, "USER"); break; default: - error(2); + error(lsym); } } if (propDef.constant && !propDef.write.isNull()) { @@ -1395,13 +1478,25 @@ void Moc::parsePropertyAttributes(PropertyDef &propDef) 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) +void Moc::parseProperty(ClassDef *def, Moc::PropertyMode mode) { next(LPAREN); PropertyDef propDef; - createPropertyDef(propDef, int(def->propertyList.size())); + createPropertyDef(propDef, int(def->propertyList.size()), mode); next(RPAREN); def->propertyList += propDef; @@ -1422,9 +1517,11 @@ void Moc::parsePluginData(ClassDef *def) } else if (l == "FILE") { next(STRING_LITERAL); QByteArray metaDataFile = unquotedLexem(); - QFileInfo fi(QFileInfo(QString::fromLocal8Bit(currentFilenames.top().constData())).dir(), QString::fromLocal8Bit(metaDataFile.constData())); - for (int j = 0; j < includes.size() && !fi.exists(); ++j) { - const IncludePath &p = includes.at(j); + 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; @@ -1487,7 +1584,7 @@ QByteArray Moc::parsePropertyAccessor() return accessor; } -void Moc::parsePrivateProperty(ClassDef *def) +void Moc::parsePrivateProperty(ClassDef *def, Moc::PropertyMode mode) { next(LPAREN); PropertyDef propDef; @@ -1495,7 +1592,7 @@ void Moc::parsePrivateProperty(ClassDef *def) next(COMMA); - createPropertyDef(propDef, int(def->propertyList.size())); + createPropertyDef(propDef, int(def->propertyList.size()), mode); def->propertyList += propDef; } @@ -1593,7 +1690,7 @@ void Moc::parseInterfaces(ClassDef *def) } } // resolve from classnames to interface ids - for (int i = 0; i < iface.count(); ++i) { + for (qsizetype i = 0; i < iface.size(); ++i) { const QByteArray iid = interface2IdMap.value(iface.at(i).className); if (iid.isEmpty()) error("Undefined interface"); @@ -1662,11 +1759,7 @@ void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access) funcDef.access = access; parseFunction(&funcDef, true); def->slotList += funcDef; - while (funcDef.arguments.size() > 0 && funcDef.arguments.constLast().isDefault) { - funcDef.wasCloned = true; - funcDef.arguments.removeLast(); - def->slotList += funcDef; - } + handleDefaultArguments(&def->slotList, funcDef); if (funcDef.revision > 0) ++def->revisionedMethods; @@ -1674,7 +1767,7 @@ void Moc::parseSlotInPrivate(ClassDef *def, FunctionDef::Access access) QByteArray Moc::lexemUntil(Token target) { - int from = index; + qsizetype from = index; until(target); QByteArray s; while (from <= index) { @@ -1708,9 +1801,9 @@ bool Moc::until(Token target) { } //when searching commas within the default argument, we should take care of template depth (anglecount) - // unfortunatelly, we do not have enough semantic information to know if '<' is the operator< or + // 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. - int possible = -1; + qsizetype possible = -1; while (index < symbols.size()) { Token t = symbols.at(index++).token; @@ -1774,7 +1867,8 @@ bool Moc::until(Token target) { void Moc::checkSuperClasses(ClassDef *def) { - const QByteArray firstSuperclass = def->superclassList.value(0).first; + Q_ASSERT(!def->superclassList.isEmpty()); + const QByteArray &firstSuperclass = def->superclassList.at(0).classname; if (!knownQObjectClasses.contains(firstSuperclass)) { // enable once we /require/ include paths @@ -1789,8 +1883,18 @@ void Moc::checkSuperClasses(ClassDef *def) #endif return; } - for (int i = 1; i < def->superclassList.count(); ++i) { - const QByteArray superClass = def->superclassList.at(i).first; + + 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 " @@ -1804,14 +1908,7 @@ void Moc::checkSuperClasses(ClassDef *def) } if (interface2IdMap.contains(superClass)) { - bool registeredInterface = false; - for (int i = 0; i < def->interfaceList.count(); ++i) - if (def->interfaceList.at(i).constFirst().className == superClass) { - registeredInterface = true; - break; - } - - if (!registeredInterface) { + if (!isRegisteredInterface(superClass)) { const QByteArray msg = "Class " + def->classname @@ -1829,34 +1926,30 @@ void Moc::checkSuperClasses(ClassDef *def) void Moc::checkProperties(ClassDef *cdef) { // - // specify get function, for compatibiliy we accept functions + // specify get function, for compatibility we accept functions // returning pointers, or const char * for QByteArray. // - QDuplicateTracker<QByteArray> definedProperties(cdef->propertyList.count()); - for (int i = 0; i < cdef->propertyList.count(); ++i) { - PropertyDef &p = cdef->propertyList[i]; + 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()) { - const int rewind = index; - if (p.location >= 0) - index = p.location; 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."; - warning(msg.constData()); - index = rewind; - if (p.write.isEmpty()) { - cdef->propertyList.removeAt(i); - --i; - } - continue; + 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 (int j = 0; j < cdef->publicList.count(); ++j) { - const FunctionDef &f = cdef->publicList.at(j); + 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 @@ -1882,7 +1975,7 @@ void Moc::checkProperties(ClassDef *cdef) } if (!p.notify.isEmpty()) { int notifyId = -1; - for (int j = 0; j < cdef->signalList.count(); ++j) { + for (int j = 0; j < int(cdef->signalList.size()); ++j) { const FunctionDef &f = cdef->signalList.at(j); if (f.name != p.notify) { continue; @@ -1893,12 +1986,12 @@ void Moc::checkProperties(ClassDef *cdef) } p.notifyId = notifyId; if (notifyId == -1) { - int index = cdef->nonClassSignalList.indexOf(p.notify); + const int index = int(cdef->nonClassSignalList.indexOf(p.notify)); if (index == -1) { cdef->nonClassSignalList << p.notify; - p.notifyId = -1 - cdef->nonClassSignalList.count(); + p.notifyId = int(-1 - cdef->nonClassSignalList.size()); } else { - p.notifyId = -2 - index; + p.notifyId = int(-2 - index); } } } @@ -1908,19 +2001,19 @@ void Moc::checkProperties(ClassDef *cdef) QJsonObject ClassDef::toJson() const { QJsonObject cls; - cls[QLatin1String("className")] = QString::fromUtf8(classname.constData()); - cls[QLatin1String("qualifiedClassName")] = QString::fromUtf8(qualified.constData()); + cls["className"_L1] = QString::fromUtf8(classname.constData()); + cls["qualifiedClassName"_L1] = QString::fromUtf8(qualified.constData()); QJsonArray classInfos; - for (const auto &info: qAsConst(classInfoList)) { + for (const auto &info: std::as_const(classInfoList)) { QJsonObject infoJson; - infoJson[QLatin1String("name")] = QString::fromUtf8(info.name); - infoJson[QLatin1String("value")] = QString::fromUtf8(info.value); + infoJson["name"_L1] = QString::fromUtf8(info.name); + infoJson["value"_L1] = QString::fromUtf8(info.value); classInfos.append(infoJson); } if (classInfos.size()) - cls[QLatin1String("classInfos")] = classInfos; + cls["classInfos"_L1] = classInfos; const auto appendFunctions = [&cls](const QString &type, const QList<FunctionDef> &funcs) { QJsonArray jsonFuncs; @@ -1932,59 +2025,59 @@ QJsonObject ClassDef::toJson() const cls[type] = jsonFuncs; }; - appendFunctions(QLatin1String("signals"), signalList); - appendFunctions(QLatin1String("slots"), slotList); - appendFunctions(QLatin1String("constructors"), constructorList); - appendFunctions(QLatin1String("methods"), methodList); + appendFunctions("signals"_L1, signalList); + appendFunctions("slots"_L1, slotList); + appendFunctions("constructors"_L1, constructorList); + appendFunctions("methods"_L1, methodList); QJsonArray props; - for (const PropertyDef &propDef: qAsConst(propertyList)) + for (const PropertyDef &propDef: std::as_const(propertyList)) props.append(propDef.toJson()); if (!props.isEmpty()) - cls[QLatin1String("properties")] = props; + cls["properties"_L1] = props; if (hasQObject) - cls[QLatin1String("object")] = true; + cls["object"_L1] = true; if (hasQGadget) - cls[QLatin1String("gadget")] = true; + cls["gadget"_L1] = true; if (hasQNamespace) - cls[QLatin1String("namespace")] = true; + cls["namespace"_L1] = true; QJsonArray superClasses; - for (const auto &super: qAsConst(superclassList)) { - const auto name = super.first; - const auto access = super.second; + for (const auto &super: std::as_const(superclassList)) { QJsonObject superCls; - superCls[QLatin1String("name")] = QString::fromUtf8(name); - FunctionDef::accessToJson(&superCls, access); + 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[QLatin1String("superClasses")] = superClasses; + cls["superClasses"_L1] = superClasses; QJsonArray enums; - for (const EnumDef &enumDef: qAsConst(enumList)) + for (const EnumDef &enumDef: std::as_const(enumList)) enums.append(enumDef.toJson(*this)); if (!enums.isEmpty()) - cls[QLatin1String("enums")] = enums; + cls["enums"_L1] = enums; QJsonArray ifaces; for (const QList<Interface> &ifaceList : interfaceList) { QJsonArray jsonList; for (const Interface &iface: ifaceList) { QJsonObject ifaceJson; - ifaceJson[QLatin1String("id")] = QString::fromUtf8(iface.interfaceId); - ifaceJson[QLatin1String("className")] = QString::fromUtf8(iface.className); + ifaceJson["id"_L1] = QString::fromUtf8(iface.interfaceId); + ifaceJson["className"_L1] = QString::fromUtf8(iface.className); jsonList.append(ifaceJson); } ifaces.append(jsonList); } if (!ifaces.isEmpty()) - cls[QLatin1String("interfaces")] = ifaces; + cls["interfaces"_L1] = ifaces; return cls; } @@ -1992,22 +2085,25 @@ QJsonObject ClassDef::toJson() const QJsonObject FunctionDef::toJson() const { QJsonObject fdef; - fdef[QLatin1String("name")] = QString::fromUtf8(name); + fdef["name"_L1] = QString::fromUtf8(name); if (!tag.isEmpty()) - fdef[QLatin1String("tag")] = QString::fromUtf8(tag); - fdef[QLatin1String("returnType")] = QString::fromUtf8(normalizedType); + 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[QLatin1String("arguments")] = args; + fdef["arguments"_L1] = args; accessToJson(&fdef, access); if (revision > 0) - fdef[QLatin1String("revision")] = revision; + fdef["revision"_L1] = revision; + + if (wasCloned) + fdef["isCloned"_L1] = true; return fdef; } @@ -2015,30 +2111,30 @@ QJsonObject FunctionDef::toJson() const void FunctionDef::accessToJson(QJsonObject *obj, FunctionDef::Access acs) { switch (acs) { - case Private: (*obj)[QLatin1String("access")] = QLatin1String("private"); break; - case Public: (*obj)[QLatin1String("access")] = QLatin1String("public"); break; - case Protected: (*obj)[QLatin1String("access")] = QLatin1String("protected"); break; + 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[QLatin1String("type")] = QString::fromUtf8(normalizedType); + arg["type"_L1] = QString::fromUtf8(normalizedType); if (!name.isEmpty()) - arg[QLatin1String("name")] = QString::fromUtf8(name); + arg["name"_L1] = QString::fromUtf8(name); return arg; } QJsonObject PropertyDef::toJson() const { QJsonObject prop; - prop[QLatin1String("name")] = QString::fromUtf8(name); - prop[QLatin1String("type")] = QString::fromUtf8(type); + 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[QLatin1String(str)] = QString::fromUtf8(member); + prop[QLatin1StringView(str)] = QString::fromUtf8(member); }; jsonify("member", member); @@ -2057,7 +2153,7 @@ QJsonObject PropertyDef::toJson() const value = false; else value = QString::fromUtf8(boolOrString); // function name to query at run-time - prop[QLatin1String(str)] = value; + prop[QLatin1StringView(str)] = value; }; jsonifyBoolOrString("designable", designable); @@ -2065,12 +2161,12 @@ QJsonObject PropertyDef::toJson() const jsonifyBoolOrString("stored", stored); jsonifyBoolOrString("user", user); - prop[QLatin1String("constant")] = constant; - prop[QLatin1String("final")] = final; - prop[QLatin1String("required")] = required; - prop[QLatin1String("index")] = relativeIndex; + prop["constant"_L1] = constant; + prop["final"_L1] = final; + prop["required"_L1] = required; + prop["index"_L1] = relativeIndex; if (revision > 0) - prop[QLatin1String("revision")] = revision; + prop["revision"_L1] = revision; return prop; } @@ -2078,19 +2174,40 @@ QJsonObject PropertyDef::toJson() const QJsonObject EnumDef::toJson(const ClassDef &cdef) const { QJsonObject def; - def[QLatin1String("name")] = QString::fromUtf8(name); + def["name"_L1] = QString::fromUtf8(name); if (!enumName.isEmpty()) - def[QLatin1String("alias")] = QString::fromUtf8(enumName); - def[QLatin1String("isFlag")] = cdef.enumDeclarations.value(name); - def[QLatin1String("isClass")] = isEnumClass; + 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[QLatin1String("values")] = valueArr; + 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/src/tools/moc/moc.h b/src/tools/moc/moc.h index 1c2d6624fa..c1759fb0a3 100644 --- a/src/tools/moc/moc.h +++ b/src/tools/moc/moc.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 @@ -32,13 +7,13 @@ #include "parser.h" #include <qstringlist.h> #include <qmap.h> -#include <qpair.h> #include <qjsondocument.h> #include <qjsonarray.h> #include <qjsonobject.h> -#include <qversionnumber.h> +#include <qtyperevision.h> #include <stdio.h> -#include <ctype.h> + +#include <private/qtools_p.h> QT_BEGIN_NAMESPACE @@ -67,10 +42,12 @@ 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); @@ -126,8 +103,10 @@ Q_DECLARE_TYPEINFO(FunctionDef, Q_RELOCATABLE_TYPE); struct PropertyDef { 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); } @@ -142,7 +121,7 @@ struct PropertyDef bool required = false; int relativeIndex = -1; // property index in current metaobject - int location = -1; // token index, used for error reporting + qsizetype location = -1; // token index, used for error reporting QJsonObject toJson() const; }; @@ -172,12 +151,19 @@ struct BaseDef { QMap<QByteArray, bool> enumDeclarations; QList<EnumDef> enumList; QMap<QByteArray, QByteArray> flagAliases; - int begin = 0; - int end = 0; + qsizetype begin = 0; + qsizetype end = 0; +}; + +struct SuperClass { + QByteArray classname; + QByteArray qualified; + FunctionDef::Access access; }; +Q_DECLARE_TYPEINFO(SuperClass, Q_RELOCATABLE_TYPE); struct ClassDef : BaseDef { - QList<QPair<QByteArray, FunctionDef::Access>> superclassList; + QList<SuperClass> superclassList; struct Interface { @@ -221,6 +207,8 @@ Q_DECLARE_TYPEINFO(NamespaceDef, Q_RELOCATABLE_TYPE); class Moc : public Parser { public: + enum PropertyMode { Named, Anonymous }; + Moc() : noInclude(false), mustIncludeQPluginH(false), requireCompleteTypes(false) {} @@ -253,6 +241,10 @@ public: 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); @@ -262,9 +254,11 @@ public: void parseSlots(ClassDef *def, FunctionDef::Access access); void parseSignals(ClassDef *def); - void parseProperty(ClassDef *def); + void parseProperty(ClassDef *def, PropertyMode mode); void parsePluginData(ClassDef *def); - void createPropertyDef(PropertyDef &def, int propertyIndex); + + void createPropertyDef(PropertyDef &def, int propertyIndex, PropertyMode mode); + void parsePropertyAttributes(PropertyDef &propDef); void parseEnumOrFlag(BaseDef *def, bool isFlag); void parseFlag(BaseDef *def); @@ -277,7 +271,7 @@ public: void parseMocInclude(); void parseSlotInPrivate(ClassDef *def, FunctionDef::Access access); QByteArray parsePropertyAccessor(); - void parsePrivateProperty(ClassDef *def); + void parsePrivateProperty(ClassDef *def, PropertyMode mode); void parseFunctionArguments(FunctionDef *def); @@ -295,14 +289,17 @@ public: void checkSuperClasses(ClassDef *def); void checkProperties(ClassDef* cdef); + bool testForFunctionModifiers(FunctionDef *def); + + void checkListSizes(const ClassDef &def); }; 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/src/tools/moc/outputrevision.h b/src/tools/moc/outputrevision.h index e8d2d1b1b9..3bc5a872ed 100644 --- a/src/tools/moc/outputrevision.h +++ b/src/tools/moc/outputrevision.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 diff --git a/src/tools/moc/parser.cpp b/src/tools/moc/parser.cpp index 4b67e3a99a..1cfb8ce486 100644 --- a/src/tools/moc/parser.cpp +++ b/src/tools/moc/parser.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 "parser.h" #include "utils.h" @@ -33,42 +8,80 @@ QT_BEGIN_NAMESPACE -#ifdef USE_LEXEM_STORE -Symbol::LexemStore Symbol::lexemStore; -#endif - static const char *error_msg = nullptr; +/*! \internal + Base implementation for printing diagnostic messages. + + For example: + "/path/to/file:line:column: error: %s\n" + '%s' is replaced by \a msg. (Currently "column" is always 1). + + If sym.lineNum is -1, the line and column parts aren't printed: + "/path/to/file: error: %s\n" + + \a formatStringSuffix specifies the type of the message e.g.: + "error: %s\n" + "warning: %s\n" + "note: %s\n" + "Parse error at %s\n" (from defaultErrorMsg()) +*/ +void Parser::printMsg(QByteArrayView formatStringSuffix, QByteArrayView msg, const Symbol &sym) +{ + if (sym.lineNum != -1) { #ifdef Q_CC_MSVC -#define ErrorFormatString "%s(%d:%d): " + QByteArray formatString = "%s(%d:%d): " + formatStringSuffix; #else -#define ErrorFormatString "%s:%d:%d: " + QByteArray formatString = "%s:%d:%d: " + formatStringSuffix; #endif + fprintf(stderr, formatString.constData(), + currentFilenames.top().constData(), sym.lineNum, 1, msg.data()); + } else { + QByteArray formatString = "%s: " + formatStringSuffix; + fprintf(stderr, formatString.constData(), + currentFilenames.top().constData(), msg.data()); + } +} + +void Parser::defaultErrorMsg(const Symbol &sym) +{ + if (sym.lineNum != -1) + printMsg("error: Parse error at \"%s\"\n", sym.lexem().data(), sym); + else + printMsg("error: could not parse file\n", "", sym); +} -void Parser::error(int rollback) { - index -= rollback; - error(); +void Parser::error(const Symbol &sym) +{ + defaultErrorMsg(sym); + exit(EXIT_FAILURE); } -void Parser::error(const char *msg) { + +void Parser::error(const char *msg) +{ if (msg || error_msg) - fprintf(stderr, ErrorFormatString "error: %s\n", - currentFilenames.top().constData(), symbol().lineNum, 1, msg?msg:error_msg); + printMsg("error: %s\n", + msg ? msg : error_msg, + index > 0 ? symbol() : Symbol{}); else - fprintf(stderr, ErrorFormatString "error: Parse error at \"%s\"\n", - currentFilenames.top().constData(), symbol().lineNum, 1, symbol().lexem().data()); + defaultErrorMsg(symbol()); + exit(EXIT_FAILURE); } +void Parser::warning(const Symbol &sym, QByteArrayView msg) +{ + if (displayWarnings) + printMsg("warning: %s\n", msg, sym); +} + void Parser::warning(const char *msg) { - if (displayWarnings && msg) - fprintf(stderr, ErrorFormatString "warning: %s\n", - currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg); + warning(index > 0 ? symbol() : Symbol{}, msg); } void Parser::note(const char *msg) { if (displayNotes && msg) - fprintf(stderr, ErrorFormatString "note: %s\n", - currentFilenames.top().constData(), qMax(0, index > 0 ? symbol().lineNum : 0), 1, msg); + printMsg("note: %s\n", msg, index > 0 ? symbol() : Symbol{}); } QT_END_NAMESPACE diff --git a/src/tools/moc/parser.h b/src/tools/moc/parser.h index f014d7e6b5..6fe982a1ce 100644 --- a/src/tools/moc/parser.h +++ b/src/tools/moc/parser.h @@ -1,35 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 PARSER_H #define PARSER_H #include "symbols.h" +#include <QtCore/qbytearrayview.h> #include <stack> @@ -40,7 +16,7 @@ class Parser public: Parser():index(0), displayWarnings(true), displayNotes(true) {} Symbols symbols; - int index; + qsizetype index; bool displayWarnings; bool displayNotes; @@ -68,11 +44,15 @@ public: inline QByteArray lexem() { return symbols.at(index-1).lexem();} inline QByteArray unquotedLexem() { return symbols.at(index-1).unquotedLexem();} inline const Symbol &symbol() { return symbols.at(index-1);} + inline const Symbol &symbolAt(qsizetype idx) { return symbols.at(idx); } - Q_NORETURN void error(int rollback); + Q_NORETURN void error(const Symbol &symbol); Q_NORETURN void error(const char *msg = nullptr); void warning(const char * = nullptr); + void warning(const Symbol &sym, QByteArrayView msg); void note(const char * = nullptr); + void defaultErrorMsg(const Symbol &sym); + void printMsg(QByteArrayView formatStringSuffix, QByteArrayView msg, const Symbol &sym); }; @@ -87,7 +67,7 @@ inline bool Parser::test(Token token) inline Token Parser::lookup(int k) { - const int l = index - 1 + k; + const qsizetype l = index - 1 + k; return l < symbols.size() ? symbols.at(l).token : NOTOKEN; } diff --git a/src/tools/moc/ppkeywords.cpp b/src/tools/moc/ppkeywords.cpp index b94abf8cd8..dc13f3db95 100644 --- a/src/tools/moc/ppkeywords.cpp +++ b/src/tools/moc/ppkeywords.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 // auto generated // DO NOT EDIT. diff --git a/src/tools/moc/preprocessor.cpp b/src/tools/moc/preprocessor.cpp index c6e84c0913..11ea8d417e 100644 --- a/src/tools/moc/preprocessor.cpp +++ b/src/tools/moc/preprocessor.cpp @@ -1,31 +1,6 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.org> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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. +// Copyright (C) 2014 Olivier Goffart <ogoffart@woboq.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "preprocessor.h" #include "utils.h" @@ -33,9 +8,12 @@ #include <qfile.h> #include <qdir.h> #include <qfileinfo.h> +#include <qvarlengtharray.h> QT_BEGIN_NAMESPACE +using namespace QtMiscUtils; + #include "ppkeywords.cpp" #include "keywords.cpp" @@ -236,7 +214,9 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso data -= 2; break; case DIGIT: - while (is_digit_char(*data) || *data == '\'') + { + bool hasSeenTokenSeparator = false;; + while (isAsciiDigit(*data) || (hasSeenTokenSeparator = *data == '\'')) ++data; if (!*data || *data != '.') { token = INTEGER_LITERAL; @@ -245,22 +225,30 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso || *data == 'b' || *data == 'B') && *lexem == '0') { ++data; - while (is_hex_char(*data) || *data == '\'') + while (isHexDigit(*data) || (hasSeenTokenSeparator = *data == '\'')) + ++data; + } else if (*data == 'L') // TODO: handle other suffixes + ++data; + if (!hasSeenTokenSeparator) { + while (is_ident_char(*data)) { ++data; + token = IDENTIFIER; + } } break; } token = FLOATING_LITERAL; ++data; Q_FALLTHROUGH(); + } case FLOATING_LITERAL: - while (is_digit_char(*data) || *data == '\'') + while (isAsciiDigit(*data) || *data == '\'') ++data; if (*data == '+' || *data == '-') ++data; if (*data == 'e' || *data == 'E') { ++data; - while (is_digit_char(*data) || *data == '\'') + while (isAsciiDigit(*data) || *data == '\'') ++data; } if (*data == 'f' || *data == 'F' @@ -339,16 +327,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso continue; //ignore } } -#ifdef USE_LEXEM_STORE - if (!Preprocessor::preprocessOnly - && token != IDENTIFIER - && token != STRING_LITERAL - && token != FLOATING_LITERAL - && token != INTEGER_LITERAL) - symbols += Symbol(lineNum, token); - else -#endif - symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem); + symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem); } else { // Preprocessor @@ -414,7 +393,7 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso token = PP_CHARACTER_LITERAL; break; case PP_DIGIT: - while (is_digit_char(*data) || *data == '\'') + while (isAsciiDigit(*data) || *data == '\'') ++data; if (!*data || *data != '.') { token = PP_INTEGER_LITERAL; @@ -422,22 +401,23 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso (*data == 'x' || *data == 'X') && *lexem == '0') { ++data; - while (is_hex_char(*data) || *data == '\'') + while (isHexDigit(*data) || *data == '\'') ++data; - } + } else if (*data == 'L') // TODO: handle other suffixes + ++data; break; } token = PP_FLOATING_LITERAL; ++data; Q_FALLTHROUGH(); case PP_FLOATING_LITERAL: - while (is_digit_char(*data) || *data == '\'') + while (isAsciiDigit(*data) || *data == '\'') ++data; if (*data == '+' || *data == '-') ++data; if (*data == 'e' || *data == 'E') { ++data; - while (is_digit_char(*data) || *data == '\'') + while (isAsciiDigit(*data) || *data == '\'') ++data; } if (*data == 'f' || *data == 'F' @@ -519,22 +499,14 @@ Symbols Preprocessor::tokenize(const QByteArray& input, int lineNum, Preprocesso } if (mode == PreparePreprocessorStatement) continue; -#ifdef USE_LEXEM_STORE - if (token != PP_IDENTIFIER - && token != PP_STRING_LITERAL - && token != PP_FLOATING_LITERAL - && token != PP_INTEGER_LITERAL) - symbols += Symbol(lineNum, token); - else -#endif - symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem); + symbols += Symbol(lineNum, token, input, lexem-begin, data-lexem); } } symbols += Symbol(); // eof symbol return symbols; } -void Preprocessor::macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index, +void Preprocessor::macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, qsizetype &index, int lineNum, bool one, const QSet<QByteArray> &excludeSymbols) { SymbolStack symbols; @@ -642,19 +614,22 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym HashHash } mode = Normal; - for (int i = 0; i < macro.symbols.size(); ++i) { - const Symbol &s = macro.symbols.at(i); + const auto end = macro.symbols.cend(); + auto it = macro.symbols.cbegin(); + const auto lastSym = std::prev(macro.symbols.cend(), !macro.symbols.isEmpty() ? 1 : 0); + for (; it != end; ++it) { + const Symbol &s = *it; if (s.token == HASH || s.token == PP_HASHHASH) { mode = (s.token == HASH ? Hash : HashHash); continue; } - int index = macro.arguments.indexOf(s); + const qsizetype index = macro.arguments.indexOf(s); if (mode == Normal) { if (index >= 0 && index < arguments.size()) { // each argument undoergoes macro expansion if it's not used as part of a # or ## - if (i == macro.symbols.size() - 1 || macro.symbols.at(i + 1).token != PP_HASHHASH) { + if (it == lastSym || std::next(it)->token != PP_HASHHASH) { Symbols arg = arguments.at(index); - int idx = 1; + qsizetype idx = 1; macroExpand(&expansion, that, arg, idx, lineNum, false, symbols.excludeSymbols()); } else { expansion += arguments.at(index); @@ -673,9 +648,9 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym const Symbols &arg = arguments.at(index); QByteArray stringified; - for (int i = 0; i < arg.size(); ++i) { - stringified += arg.at(i).lexem(); - } + for (const Symbol &sym : arg) + stringified += sym.lexem(); + stringified.replace('"', "\\\""); stringified.prepend('"'); stringified.append('"'); @@ -709,8 +684,8 @@ Symbols Preprocessor::macroExpandIdentifier(Preprocessor *that, SymbolStack &sym if (index >= 0 && index < arguments.size()) { const Symbols &arg = arguments.at(index); - for (int i = 1; i < arg.size(); ++i) - expansion += arg.at(i); + if (!arg.isEmpty()) + expansion.append(arg.cbegin() + 1, arg.cend()); } } mode = Normal; @@ -951,7 +926,11 @@ int PP_Expression::primary_expression() test(PP_RPAREN); } else { next(); - value = lexem().toInt(nullptr, 0); + const QByteArray &lex = lexem(); + auto lexView = QByteArrayView(lex); + if (lex.endsWith('L')) + lexView.chop(1); + value = lexView.toInt(nullptr, 0); } return value; } @@ -990,7 +969,7 @@ static void mergeStringLiterals(Symbols *_symbols) for (Symbols::iterator i = symbols.begin(); i != symbols.end(); ++i) { if (i->token == STRING_LITERAL) { Symbols::Iterator mergeSymbol = i; - int literalsLength = mergeSymbol->len; + qsizetype literalsLength = mergeSymbol->len; while (++i != symbols.end() && i->token == STRING_LITERAL) literalsLength += i->len - 2; // no quotes @@ -1004,7 +983,7 @@ static void mergeStringLiterals(Symbols *_symbols) for (Symbols::iterator j = mergeSymbol + 1; j != i; ++j) mergeSymbolLexem.append(j->lex.constData() + j->from + 1, j->len - 2); // append j->unquotedLexem() mergeSymbolLexem.append('"'); - mergeSymbol->len = mergeSymbol->lex.length(); + mergeSymbol->len = mergeSymbol->lex.size(); mergeSymbol->from = 0; i = symbols.erase(mergeSymbol + 1, i); } @@ -1015,13 +994,21 @@ static void mergeStringLiterals(Symbols *_symbols) } static QByteArray searchIncludePaths(const QList<Parser::IncludePath> &includepaths, - const QByteArray &include) + const QByteArray &include, + const bool debugIncludes) { QFileInfo fi; - for (int j = 0; j < includepaths.size() && !fi.exists(); ++j) { - const Parser::IncludePath &p = includepaths.at(j); + + if (Q_UNLIKELY(debugIncludes)) { + fprintf(stderr, "debug-includes: searching for '%s'\n", include.constData()); + } + + for (const Parser::IncludePath &p : includepaths) { + if (fi.exists()) + break; + if (p.isFrameworkPath) { - const int slashPos = include.indexOf('/'); + const qsizetype slashPos = include.indexOf('/'); if (slashPos == -1) continue; fi.setFile(QString::fromLocal8Bit(p.path + '/' + include.left(slashPos) + ".framework/Headers/"), @@ -1029,6 +1016,12 @@ static QByteArray searchIncludePaths(const QList<Parser::IncludePath> &includepa } else { fi.setFile(QString::fromLocal8Bit(p.path), QString::fromLocal8Bit(include)); } + + if (Q_UNLIKELY(debugIncludes)) { + const auto candidate = fi.filePath().toLocal8Bit(); + fprintf(stderr, "debug-includes: considering '%s'\n", candidate.constData()); + } + // try again, maybe there's a file later in the include paths with the same name // (186067) if (fi.isDir()) { @@ -1037,9 +1030,20 @@ static QByteArray searchIncludePaths(const QList<Parser::IncludePath> &includepa } } - if (!fi.exists() || fi.isDir()) + if (!fi.exists() || fi.isDir()) { + if (Q_UNLIKELY(debugIncludes)) { + fprintf(stderr, "debug-includes: can't find '%s'\n", include.constData()); + } return QByteArray(); - return fi.canonicalFilePath().toLocal8Bit(); + } + + const auto result = fi.canonicalFilePath().toLocal8Bit(); + + if (Q_UNLIKELY(debugIncludes)) { + fprintf(stderr, "debug-includes: found '%s'\n", result.constData()); + } + + return result; } QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteArray &relativeTo) @@ -1053,7 +1057,11 @@ QByteArray Preprocessor::resolveInclude(const QByteArray &include, const QByteAr auto it = nonlocalIncludePathResolutionCache.find(include); if (it == nonlocalIncludePathResolutionCache.end()) - it = nonlocalIncludePathResolutionCache.insert(include, searchIncludePaths(includes, include)); + it = nonlocalIncludePathResolutionCache.insert(include, + searchIncludePaths( + includes, + include, + debugIncludes)); return it.value(); } @@ -1096,7 +1104,7 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed) continue; Symbols saveSymbols = symbols; - int saveIndex = index; + qsizetype saveIndex = index; // phase 1: get rid of backslash-newlines input = cleaned(input); @@ -1131,14 +1139,14 @@ void Preprocessor::preprocess(const QByteArray &filename, Symbols &preprocessed) } else { macro.isFunction = false; } - int start = index; + qsizetype start = index; until(PP_NEWLINE); macro.symbols.reserve(index - start - 1); // remove whitespace where there shouldn't be any: // Before and after the macro, after a # and around ## Token lastToken = HASH; // skip shitespace at the beginning - for (int i = start; i < index - 1; ++i) { + for (qsizetype i = start; i < index - 1; ++i) { Token token = symbols.at(i).token; if (token == WHITESPACE) { if (lastToken == PP_HASH || lastToken == HASH || @@ -1281,7 +1289,7 @@ void Preprocessor::parseDefineArguments(Macro *m) if (!test(PP_RPAREN)) error("missing ')' in macro argument list"); break; - } else if (!is_identifier(l.constData(), l.length())) { + } else if (!is_identifier(l.constData(), l.size())) { error("Unexpected character in macro argument list."); } } @@ -1318,4 +1326,10 @@ void Preprocessor::until(Token t) ; } +void Preprocessor::setDebugIncludes(bool value) +{ + debugIncludes = value; +} + + QT_END_NAMESPACE diff --git a/src/tools/moc/preprocessor.h b/src/tools/moc/preprocessor.h index 39f56d6e92..3509e83dce 100644 --- a/src/tools/moc/preprocessor.h +++ b/src/tools/moc/preprocessor.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 PREPROCESSOR_H #define PREPROCESSOR_H @@ -45,11 +20,7 @@ struct Macro Symbols symbols; }; -#ifdef USE_LEXEM_STORE -typedef QByteArray MacroName; -#else typedef SubArray MacroName; -#endif typedef QHash<MacroName, Macro> Macros; class QFile; @@ -73,18 +44,22 @@ public: void substituteUntilNewline(Symbols &substituted); static Symbols macroExpandIdentifier(Preprocessor *that, SymbolStack &symbols, int lineNum, QByteArray *macroName); - static void macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, int &index, int lineNum, bool one, - const QSet<QByteArray> &excludeSymbols = QSet<QByteArray>()); + static void macroExpand(Symbols *into, Preprocessor *that, const Symbols &toExpand, + qsizetype &index, int lineNum, bool one, + const QSet<QByteArray> &excludeSymbols = QSet<QByteArray>()); int evaluateCondition(); enum TokenizeMode { TokenizeCpp, TokenizePreprocessor, PreparePreprocessorStatement, TokenizePreprocessorStatement, TokenizeInclude, PrepareDefine, TokenizeDefine }; static Symbols tokenize(const QByteArray &input, int lineNum = 1, TokenizeMode mode = TokenizeCpp); + void setDebugIncludes(bool value); + private: void until(Token); void preprocess(const QByteArray &filename, Symbols &preprocessed); + bool debugIncludes = false; }; QT_END_NAMESPACE diff --git a/src/tools/moc/symbols.h b/src/tools/moc/symbols.h index bbb1312cdc..869f7c793f 100644 --- a/src/tools/moc/symbols.h +++ b/src/tools/moc/symbols.h @@ -1,111 +1,62 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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. +// Copyright (C) 2013 Olivier Goffart <ogoffart@woboq.com> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef SYMBOLS_H #define SYMBOLS_H #include "token.h" #include <qdebug.h> -#include <qhash.h> +#include <qhashfunctions.h> #include <qlist.h> #include <qstack.h> #include <qstring.h> +#include <qset.h> QT_BEGIN_NAMESPACE -//#define USE_LEXEM_STORE - struct SubArray { - inline SubArray():from(0),len(-1){} + inline SubArray() = default; inline SubArray(const QByteArray &a):array(a),from(0), len(a.size()){} inline SubArray(const char *s):array(s),from(0) { len = array.size(); } - inline SubArray(const QByteArray &a, int from, int len):array(a), from(from), len(len){} + SubArray(const QByteArray &a, qsizetype from, qsizetype len) + : array(a), from(from), len(len) + { + } QByteArray array; - int from, len; + qsizetype from = 0; + qsizetype len = -1; inline bool operator==(const SubArray &other) const { if (len != other.len) return false; - for (int i = 0; i < len; ++i) - if (array.at(from + i) != other.array.at(other.from + i)) - return false; - return true; + const auto begin = array.cbegin() + from; + const auto end = begin + len; + const auto other_begin = other.array.cbegin() + other.from; + return std::equal(begin, end, other_begin); } }; -inline size_t qHash(const SubArray &key) +inline size_t qHash(const SubArray &key, size_t seed = 0) { - return qHash(QLatin1String(key.array.constData() + key.from, key.len)); + return qHash(QLatin1StringView(key.array.constData() + key.from, key.len), seed); } struct Symbol { - -#ifdef USE_LEXEM_STORE - typedef QHash<SubArray, QHashDummyValue> LexemStore; - static LexemStore lexemStore; - - inline Symbol() : lineNum(-1),token(NOTOKEN){} - inline Symbol(int lineNum, Token token): - lineNum(lineNum), token(token){} - inline Symbol(int lineNum, Token token, const QByteArray &lexem): - lineNum(lineNum), token(token),lex(lexem){} - inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len): - lineNum(lineNum), token(token){ - LexemStore::const_iterator it = lexemStore.constFind(SubArray(lexem, from, len)); - - if (it != lexemStore.constEnd()) { - lex = it.key().array; - } else { - lex = lexem.mid(from, len); - lexemStore.insert(lex, QHashDummyValue()); - } + inline Symbol() = default; + inline Symbol(int lineNum, Token token) : lineNum(lineNum), token(token) { } + inline Symbol(int lineNum, Token token, const QByteArray &lexem) + : lineNum(lineNum), token(token), lex(lexem), len(lex.size()) + { } - int lineNum; - Token token; - inline QByteArray unquotedLexem() const { return lex.mid(1, lex.length()-2); } - inline QByteArray lexem() const { return lex; } - inline operator QByteArray() const { return lex; } - QByteArray lex; - -#else - - inline Symbol() : lineNum(-1),token(NOTOKEN), from(0),len(-1) {} - inline Symbol(int lineNum, Token token): - lineNum(lineNum), token(token), from(0), len(-1) {} - inline Symbol(int lineNum, Token token, const QByteArray &lexem): - lineNum(lineNum), token(token), lex(lexem), from(0) { len = lex.size(); } - inline Symbol(int lineNum, Token token, const QByteArray &lexem, int from, int len): - lineNum(lineNum), token(token),lex(lexem),from(from), len(len){} - int lineNum; - Token token; + Symbol(int lineNum, Token token, const QByteArray &lexem, qsizetype from, qsizetype len) + : lineNum(lineNum), token(token), lex(lexem), from(from), len(len) + { + } + int lineNum = -1; + Token token = NOTOKEN; inline QByteArray lexem() const { return lex.mid(from, len); } inline QByteArray unquotedLexem() const { return lex.mid(from+1, len-2); } inline operator SubArray() const { return SubArray(lex, from, len); } @@ -114,9 +65,8 @@ struct Symbol return SubArray(lex, from, len) == SubArray(o.lex, o.from, o.len); } QByteArray lex; - int from, len; - -#endif + qsizetype from = 0; + qsizetype len = -1; }; Q_DECLARE_TYPEINFO(Symbol, Q_RELOCATABLE_TYPE); @@ -126,7 +76,7 @@ struct SafeSymbols { Symbols symbols; QByteArray expandedMacro; QSet<QByteArray> excludedSymbols; - int index; + qsizetype index; }; Q_DECLARE_TYPEINFO(SafeSymbols, Q_RELOCATABLE_TYPE); @@ -151,13 +101,13 @@ public: inline QByteArray lexem() const { return symbol().lexem(); } inline QByteArray unquotedLexem() { return symbol().unquotedLexem(); } - bool dontReplaceSymbol(const QByteArray &name); - QSet<QByteArray> excludeSymbols(); + bool dontReplaceSymbol(const QByteArray &name) const; + QSet<QByteArray> excludeSymbols() const; }; inline bool SymbolStack::test(Token token) { - int stackPos = size() - 1; + qsizetype stackPos = size() - 1; while (stackPos >= 0 && at(stackPos).index >= at(stackPos).symbols.size()) --stackPos; if (stackPos < 0) @@ -169,21 +119,20 @@ inline bool SymbolStack::test(Token token) return false; } -inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name) +inline bool SymbolStack::dontReplaceSymbol(const QByteArray &name) const { - for (int i = 0; i < size(); ++i) { - if (name == at(i).expandedMacro || at(i).excludedSymbols.contains(name)) - return true; - } - return false; + auto matchesName = [&name](const SafeSymbols &sf) { + return name == sf.expandedMacro || sf.excludedSymbols.contains(name); + }; + return std::any_of(cbegin(), cend(), matchesName); } -inline QSet<QByteArray> SymbolStack::excludeSymbols() +inline QSet<QByteArray> SymbolStack::excludeSymbols() const { QSet<QByteArray> set; - for (int i = 0; i < size(); ++i) { - set << at(i).expandedMacro; - set += at(i).excludedSymbols; + for (const SafeSymbols &sf : *this) { + set << sf.expandedMacro; + set += sf.excludedSymbols; } return set; } diff --git a/src/tools/moc/token.cpp b/src/tools/moc/token.cpp index cf1aa102c7..bfefaff57b 100644 --- a/src/tools/moc/token.cpp +++ b/src/tools/moc/token.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 "token.h" diff --git a/src/tools/moc/token.h b/src/tools/moc/token.h index c11ec6a38c..a70808370d 100644 --- a/src/tools/moc/token.h +++ b/src/tools/moc/token.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #ifndef TOKEN_H #define TOKEN_H @@ -154,9 +129,11 @@ QT_BEGIN_NAMESPACE F(RETURN) \ F(Q_OBJECT_TOKEN) \ F(Q_GADGET_TOKEN) \ + F(Q_GADGET_EXPORT_TOKEN) \ F(Q_NAMESPACE_TOKEN) \ F(Q_NAMESPACE_EXPORT_TOKEN) \ F(Q_PROPERTY_TOKEN) \ + F(QT_ANONYMOUS_PROPERTY_TOKEN) \ F(Q_PLUGIN_METADATA_TOKEN) \ F(Q_ENUMS_TOKEN) \ F(Q_ENUM_TOKEN) \ @@ -178,6 +155,7 @@ QT_BEGIN_NAMESPACE F(Q_INVOKABLE_TOKEN) \ F(Q_SCRIPTABLE_TOKEN) \ F(Q_PRIVATE_PROPERTY_TOKEN) \ + F(QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN) \ F(Q_REVISION_TOKEN) \ F(Q_MOC_INCLUDE_TOKEN) \ F(SPECIAL_TREATMENT_MARK) \ diff --git a/src/tools/moc/util/generate.sh b/src/tools/moc/util/generate.sh index 5460d28924..6be06e5a91 100755 --- a/src/tools/moc/util/generate.sh +++ b/src/tools/moc/util/generate.sh @@ -1,37 +1,12 @@ #!/bin/sh -############################################################################# -## -## Copyright (C) 2016 The Qt Company Ltd. -## Contact: https://www.qt.io/licensing/ -## -## This file is the build configuration utility 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 set -ex qmake make -cat licenseheader.txt > ../keywords.cpp -cat licenseheader.txt > ../ppkeywords.cpp +cat licenseheader.cpp.in > ../keywords.cpp +cat licenseheader.cpp.in > ../ppkeywords.cpp ./generate_keywords >> ../keywords.cpp ./generate_keywords preprocessor >> ../ppkeywords.cpp diff --git a/src/tools/moc/util/generate_keywords.cpp b/src/tools/moc/util/generate_keywords.cpp index 28c5eeff38..a6c85af9f1 100644 --- a/src/tools/moc/util/generate_keywords.cpp +++ b/src/tools/moc/util/generate_keywords.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 <stdio.h> #include <string.h> #include <qbytearray.h> @@ -216,7 +191,9 @@ static const Keyword keywords[] = { { "Q_NAMESPACE", "Q_NAMESPACE_TOKEN" }, { "Q_NAMESPACE_EXPORT", "Q_NAMESPACE_EXPORT_TOKEN" }, { "Q_GADGET", "Q_GADGET_TOKEN" }, + { "Q_GADGET_EXPORT", "Q_GADGET_EXPORT_TOKEN" }, { "Q_PROPERTY", "Q_PROPERTY_TOKEN" }, + { "QT_ANONYMOUS_PROPERTY", "QT_ANONYMOUS_PROPERTY_TOKEN" }, { "Q_PLUGIN_METADATA", "Q_PLUGIN_METADATA_TOKEN" }, { "Q_ENUMS", "Q_ENUMS_TOKEN" }, { "Q_ENUM", "Q_ENUM_TOKEN" }, @@ -242,6 +219,7 @@ static const Keyword keywords[] = { { "Q_SLOT", "Q_SLOT_TOKEN" }, { "Q_SCRIPTABLE", "Q_SCRIPTABLE_TOKEN" }, { "Q_PRIVATE_PROPERTY", "Q_PRIVATE_PROPERTY_TOKEN" }, + { "QT_ANONYMOUS_PRIVATE_PROPERTY", "QT_ANONYMOUS_PRIVATE_PROPERTY_TOKEN" }, { "Q_REVISION", "Q_REVISION_TOKEN" }, { "Q_MOC_INCLUDE", "Q_MOC_INCLUDE_TOKEN" }, { "\n", "NEWLINE" }, diff --git a/src/tools/moc/util/generate_keywords.pro b/src/tools/moc/util/generate_keywords.pro new file mode 100644 index 0000000000..e29738c18a --- /dev/null +++ b/src/tools/moc/util/generate_keywords.pro @@ -0,0 +1,5 @@ +CONFIG -= moc +CONFIG += cmdline +QT = core + +SOURCES += generate_keywords.cpp diff --git a/src/tools/moc/util/licenseheader.cpp.in b/src/tools/moc/util/licenseheader.cpp.in new file mode 100644 index 0000000000..42958a66f5 --- /dev/null +++ b/src/tools/moc/util/licenseheader.cpp.in @@ -0,0 +1,3 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + diff --git a/src/tools/moc/util/licenseheader.txt b/src/tools/moc/util/licenseheader.txt deleted file mode 100644 index b2b02f82eb..0000000000 --- a/src/tools/moc/util/licenseheader.txt +++ /dev/null @@ -1,28 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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$ -** -****************************************************************************/ - diff --git a/src/tools/moc/utils.h b/src/tools/moc/utils.h index 4cb1d90345..0b0d70f462 100644 --- a/src/tools/moc/utils.h +++ b/src/tools/moc/utils.h @@ -1,35 +1,13 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the tools applications 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 UTILS_H #define UTILS_H #include <QtCore/qglobal.h> +#include <private/qtools_p.h> + +#include <algorithm> QT_BEGIN_NAMESPACE @@ -45,49 +23,20 @@ inline bool is_space(char s) inline bool is_ident_start(char s) { - return ((s >= 'a' && s <= 'z') - || (s >= 'A' && s <= 'Z') - || s == '_' || s == '$' - ); + using namespace QtMiscUtils; + return isAsciiLower(s) || isAsciiUpper(s) || s == '_' || s == '$'; } inline bool is_ident_char(char s) { - return ((s >= 'a' && s <= 'z') - || (s >= 'A' && s <= 'Z') - || (s >= '0' && s <= '9') - || s == '_' || s == '$' - ); + return QtMiscUtils::isAsciiLetterOrNumber(s) || s == '_' || s == '$'; } -inline bool is_identifier(const char *s, int len) +inline bool is_identifier(const char *s, qsizetype len) { if (len < 1) return false; - if (!is_ident_start(*s)) - return false; - for (int i = 1; i < len; ++i) - if (!is_ident_char(s[i])) - return false; - return true; -} - -inline bool is_digit_char(char s) -{ - return (s >= '0' && s <= '9'); -} - -inline bool is_octal_char(char s) -{ - return (s >= '0' && s <= '7'); -} - -inline bool is_hex_char(char s) -{ - return ((s >= 'a' && s <= 'f') - || (s >= 'A' && s <= 'F') - || (s >= '0' && s <= '9') - ); + return std::all_of(s, s + len, is_ident_char); } inline const char *skipQuote(const char *data) |