diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-11-05 11:14:21 +0100 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2020-11-06 08:11:53 +0000 |
commit | e21b3c5f6201c97a89b736cec17a1855870409e8 (patch) | |
tree | fedbbd89e2112346109a9cd0c1c07a252fe92556 | |
parent | b70183a78ed7a478ae9f2af19bd84535a8e69320 (diff) |
shiboken6: Split out modification classes from typesystem
Change Modification::Modifiers to be a QFlags
and remove unused functions.
Change-Id: Ia4a6b9ef06415275b33891cb04772780cd7f2d65
Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r-- | sources/shiboken6/ApiExtractor/CMakeLists.txt | 1 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/modifications.cpp | 471 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/modifications.h | 539 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/typesystem.cpp | 465 | ||||
-rw-r--r-- | sources/shiboken6/ApiExtractor/typesystem.h | 510 |
5 files changed, 1016 insertions, 970 deletions
diff --git a/sources/shiboken6/ApiExtractor/CMakeLists.txt b/sources/shiboken6/ApiExtractor/CMakeLists.txt index ec9c55364..00a376496 100644 --- a/sources/shiboken6/ApiExtractor/CMakeLists.txt +++ b/sources/shiboken6/ApiExtractor/CMakeLists.txt @@ -15,6 +15,7 @@ documentation.cpp fileout.cpp graph.cpp messages.cpp +modifications.cpp propertyspec.cpp reporthandler.cpp sourcelocation.cpp diff --git a/sources/shiboken6/ApiExtractor/modifications.cpp b/sources/shiboken6/ApiExtractor/modifications.cpp new file mode 100644 index 000000000..54b30f041 --- /dev/null +++ b/sources/shiboken6/ApiExtractor/modifications.cpp @@ -0,0 +1,471 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "modifications.h" +#include "typedatabase.h" +#include "typesystem.h" + +#include <QtCore/QDebug> + +#include <algorithm> +#include <limits> + +static inline QString callOperator() { return QStringLiteral("operator()"); } + +QString TemplateInstance::expandCode() const +{ + TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name); + if (!templateEntry) + qFatal("<insert-template> referring to non-existing template '%s'.", qPrintable(m_name)); + + QString code = templateEntry->code(); + for (auto it = replaceRules.cbegin(), end = replaceRules.cend(); it != end; ++it) + code.replace(it.key(), it.value()); + while (!code.isEmpty() && code.at(code.size() - 1).isSpace()) + code.chop(1); + QString result = QLatin1String("// TEMPLATE - ") + m_name + QLatin1String(" - START"); + if (!code.startsWith(QLatin1Char('\n'))) + result += QLatin1Char('\n'); + result += code; + result += QLatin1String("\n// TEMPLATE - ") + m_name + QLatin1String(" - END\n"); + return result; +} + +// ---------------------- CodeSnipFragment +QString CodeSnipFragment::code() const +{ + return m_instance ? m_instance->expandCode() : m_code; +} + +// ---------------------- CodeSnipAbstract +QString CodeSnipAbstract::code() const +{ + QString res; + for (const CodeSnipFragment &codeFrag : codeList) + res.append(codeFrag.code()); + + return res; +} + +void CodeSnipAbstract::addCode(const QString &code) +{ + codeList.append(CodeSnipFragment(fixSpaces(code))); +} + +static inline int firstNonBlank(QStringView s) +{ + const auto it = std::find_if(s.cbegin(), s.cend(), + [] (QChar c) { return !c.isSpace(); }); + return int(it - s.cbegin()); +} + +static inline bool isEmpty(QStringView s) +{ + return s.isEmpty() + || std::all_of(s.cbegin(), s.cend(), + [] (QChar c) { return c.isSpace(); }); +} + +QString CodeSnipAbstract::dedent(const QString &code) +{ + if (code.isEmpty()) + return code; + // Right trim if indent=0, or trim if single line + if (!code.at(0).isSpace() || !code.contains(QLatin1Char('\n'))) + return code.trimmed(); + const auto lines = QStringView{code}.split(QLatin1Char('\n')); + int spacesToRemove = std::numeric_limits<int>::max(); + for (const auto &line : lines) { + if (!isEmpty(line)) { + const int nonSpacePos = firstNonBlank(line); + if (nonSpacePos < spacesToRemove) + spacesToRemove = nonSpacePos; + if (spacesToRemove == 0) + return code; + } + } + QString result; + for (const auto &line : lines) { + if (!isEmpty(line) && spacesToRemove < line.size()) + result += line.mid(spacesToRemove).toString(); + result += QLatin1Char('\n'); + } + return result; +} + +QString CodeSnipAbstract::fixSpaces(QString code) +{ + code.remove(QLatin1Char('\r')); + // Check for XML <tag>\n<space>bla... + if (code.startsWith(QLatin1String("\n "))) + code.remove(0, 1); + while (!code.isEmpty() && code.back().isSpace()) + code.chop(1); + code = dedent(code); + if (!code.isEmpty() && !code.endsWith(QLatin1Char('\n'))) + code.append(QLatin1Char('\n')); + return code; +} + +// Prepend a line to the code, observing indentation +void CodeSnipAbstract::prependCode(QString *code, QString firstLine) +{ + while (!code->isEmpty() && code->front() == QLatin1Char('\n')) + code->remove(0, 1); + if (!code->isEmpty() && code->front().isSpace()) { + const int indent = firstNonBlank(*code); + firstLine.prepend(QString(indent, QLatin1Char(' '))); + } + if (!firstLine.endsWith(QLatin1Char('\n'))) + firstLine += QLatin1Char('\n'); + code->prepend(firstLine); +} + +// ---------------------- Modification +QString Modification::accessModifierString() const +{ + if (isPrivate()) return QLatin1String("private"); + if (isProtected()) return QLatin1String("protected"); + if (isPublic()) return QLatin1String("public"); + if (isFriendly()) return QLatin1String("friendly"); + return QString(); +} + +// ---------------------- FunctionModification +bool FunctionModification::setSignature(const QString &s, QString *errorMessage) +{ + if (s.startsWith(QLatin1Char('^'))) { + m_signaturePattern.setPattern(s); + if (!m_signaturePattern.isValid()) { + if (errorMessage) { + *errorMessage = QLatin1String("Invalid signature pattern: \"") + + s + QLatin1String("\": ") + m_signaturePattern.errorString(); + } + return false; + } + } else { + m_signature = s; + } + return true; +} + +// ---------------------- AddedFunction + +static AddedFunction::TypeInfo parseType(const QString& signature, + int startPos = 0, int *endPos = nullptr, + QString *argumentName = nullptr, + QString *defaultValue = nullptr) +{ + AddedFunction::TypeInfo result; + static const QRegularExpression regex(QLatin1String("\\w")); + Q_ASSERT(regex.isValid()); + int length = signature.length(); + int start = signature.indexOf(regex, startPos); + if (start == -1) { + if (QStringView{signature}.mid(startPos + 1, 3) == QLatin1String("...")) { // varargs + if (endPos) + *endPos = startPos + 4; + result.name = QLatin1String("..."); + } else { // error + if (endPos) + *endPos = length; + } + return result; + } + + int cantStop = 0; + QString paramString; + QChar c; + int i = start; + for (; i < length; ++i) { + c = signature[i]; + if (c == QLatin1Char('<')) + cantStop++; + if (c == QLatin1Char('>')) + cantStop--; + if (cantStop < 0) + break; // FIXME: report error? + if ((c == QLatin1Char(')') || c == QLatin1Char(',')) && !cantStop) + break; + paramString += signature[i]; + } + if (endPos) + *endPos = i; + + // Check default value + if (paramString.contains(QLatin1Char('='))) { + QStringList lst = paramString.split(QLatin1Char('=')); + paramString = lst[0].trimmed(); + if (defaultValue != nullptr) + *defaultValue = lst[1].trimmed(); + } + + // check constness + if (paramString.startsWith(QLatin1String("const "))) { + result.isConstant = true; + paramString.remove(0, sizeof("const")/sizeof(char)); + paramString = paramString.trimmed(); + } + + // Extract argument name from "T<bla,blub>* @foo@" + const int nameStartPos = paramString.indexOf(QLatin1Char('@')); + if (nameStartPos != -1) { + const int nameEndPos = paramString.indexOf(QLatin1Char('@'), nameStartPos + 1); + if (nameEndPos > nameStartPos) { + if (argumentName) + *argumentName = paramString.mid(nameStartPos + 1, nameEndPos - nameStartPos - 1); + paramString.remove(nameStartPos, nameEndPos - nameStartPos + 1); + paramString = paramString.trimmed(); + } + } + + // check reference + if (paramString.endsWith(QLatin1Char('&'))) { + result.isReference = true; + paramString.chop(1); + paramString = paramString.trimmed(); + } + // check Indirections + while (paramString.endsWith(QLatin1Char('*'))) { + result.indirections++; + paramString.chop(1); + paramString = paramString.trimmed(); + } + result.name = paramString; + + return result; +} + +AddedFunction::AddedFunction(QString signature, const QString &returnType) : + m_access(Public) +{ + Q_ASSERT(!returnType.isEmpty()); + m_returnType = parseType(returnType); + signature = signature.trimmed(); + // Skip past "operator()(...)" + const int parenStartPos = signature.startsWith(callOperator()) + ? callOperator().size() : 0; + int endPos = signature.indexOf(QLatin1Char('('), parenStartPos); + if (endPos < 0) { + m_isConst = false; + m_name = signature; + } else { + m_name = signature.left(endPos).trimmed(); + int signatureLength = signature.length(); + while (endPos < signatureLength) { + QString argumentName; + QString defaultValue; + TypeInfo arg = parseType(signature, endPos, &endPos, &argumentName, &defaultValue); + if (!arg.name.isEmpty()) + m_arguments.append({arg, argumentName, defaultValue}); + // end of parameters... + if (endPos >= signatureLength || signature[endPos] == QLatin1Char(')')) + break; + } + // is const? + m_isConst = QStringView{signature}.right(signatureLength - endPos).contains(QLatin1String("const")); + } +} + +AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& signature) +{ + return parseType(signature); +} + +void DocModification::setCode(const QString &code) +{ + m_code = CodeSnipAbstract::fixSpaces(code); +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const ReferenceCount &r) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "ReferenceCount(" << r.varName << ", action=" << r.action << ')'; + return d; +} + +QDebug operator<<(QDebug d, const CodeSnip &s) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "CodeSnip(language=" << s.language << ", position=" << s.position << ", \""; + for (const auto &f : s.codeList) { + const QString &code = f.code(); + const auto lines = QStringView{code}.split(QLatin1Char('\n')); + for (int i = 0, size = lines.size(); i < size; ++i) { + if (i) + d << "\\n"; + d << lines.at(i).trimmed(); + } + } + d << '"'; + if (!s.argumentMap.isEmpty()) { + d << ", argumentMap{"; + for (auto it = s.argumentMap.cbegin(), end = s.argumentMap.cend(); it != end; ++it) + d << it.key() << "->\"" << it.value() << '"'; + d << '}'; + } + d << ')'; + return d; +} + +void Modification::formatDebug(QDebug &d) const +{ + d << "modifiers=" << modifiers; + if (removal) + d << ", removal"; + if (!renamedToName.isEmpty()) + d << ", renamedToName=\"" << renamedToName << '"'; +} + +void FunctionModification::formatDebug(QDebug &d) const +{ + if (m_signature.isEmpty()) + d << "pattern=\"" << m_signaturePattern.pattern(); + else + d << "signature=\"" << m_signature; + d << "\", "; + Modification::formatDebug(d); + if (!association.isEmpty()) + d << ", association=\"" << association << '"'; + if (m_allowThread != TypeSystem::AllowThread::Unspecified) + d << ", allowThread=" << int(m_allowThread); + if (m_thread) + d << ", thread"; + if (m_exceptionHandling != TypeSystem::ExceptionHandling::Unspecified) + d << ", exceptionHandling=" << int(m_exceptionHandling); + if (!snips.isEmpty()) + d << ", snips=(" << snips << ')'; + if (!argument_mods.isEmpty()) + d << ", argument_mods=(" << argument_mods << ')'; +} + +QDebug operator<<(QDebug d, const ArgumentOwner &a) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "ArgumentOwner(index=" << a.index << ", action=" << a.action << ')'; + return d; +} + +QDebug operator<<(QDebug d, const ArgumentModification &a) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "ArgumentModification(index=" << a.index; + if (a.removedDefaultExpression) + d << ", removedDefaultExpression"; + if (a.removed) + d << ", removed"; + if (a.noNullPointers) + d << ", noNullPointers"; + if (a.array) + d << ", array"; + if (!a.referenceCounts.isEmpty()) + d << ", referenceCounts=" << a.referenceCounts; + if (!a.modified_type.isEmpty()) + d << ", modified_type=\"" << a.modified_type << '"'; + if (!a.replace_value.isEmpty()) + d << ", replace_value=\"" << a.replace_value << '"'; + if (!a.replacedDefaultExpression.isEmpty()) + d << ", replacedDefaultExpression=\"" << a.replacedDefaultExpression << '"'; + if (!a.ownerships.isEmpty()) + d << ", ownerships=" << a.ownerships; + if (!a.renamed_to.isEmpty()) + d << ", renamed_to=\"" << a.renamed_to << '"'; + d << ", owner=" << a.owner << ')'; + return d; +} + +QDebug operator<<(QDebug d, const FunctionModification &fm) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "FunctionModification("; + fm.formatDebug(d); + d << ')'; + return d; +} + +QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "TypeInfo("; + if (ti.isConstant) + d << "const"; + if (ti.indirections) + d << QByteArray(ti.indirections, '*'); + if (ti.isReference) + d << " &"; + d << ti.name; + d << ')'; + return d; +} + +QDebug operator<<(QDebug d, const AddedFunction::Argument &a) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "Argument("; + d << a.typeInfo; + if (!a.name.isEmpty()) + d << ' ' << a.name; + if (!a.defaultValue.isEmpty()) + d << " = " << a.defaultValue; + d << ')'; + return d; +} + +QDebug operator<<(QDebug d, const AddedFunction &af) +{ + QDebugStateSaver saver(d); + d.noquote(); + d.nospace(); + d << "AddedFunction("; + if (af.access() == AddedFunction::Protected) + d << "protected"; + if (af.isStatic()) + d << " static"; + d << af.returnType() << ' ' << af.name() << '(' << af.arguments() << ')'; + if (af.isConstant()) + d << " const"; + if (af.isDeclaration()) + d << " [declaration]"; + return d; +} +#endif // !QT_NO_DEBUG_STREAM diff --git a/sources/shiboken6/ApiExtractor/modifications.h b/sources/shiboken6/ApiExtractor/modifications.h new file mode 100644 index 000000000..3371f51ee --- /dev/null +++ b/sources/shiboken6/ApiExtractor/modifications.h @@ -0,0 +1,539 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt for Python. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MODIFICATIONS_H +#define MODIFICATIONS_H + +#include "typesystem_enums.h" +#include "typesystem_typedefs.h" + +#include <QtCore/QList> +#include <QtCore/QMap> +#include <QtCore/QRegularExpression> +#include <QtCore/QString> + +QT_BEGIN_NAMESPACE +class QDebug; +QT_END_NAMESPACE + +using ArgumentMap = QMap<int, QString>; + +class TemplateInstance +{ +public: + explicit TemplateInstance(const QString &name) : m_name(name) {} + + void addReplaceRule(const QString &name, const QString &value) + { + replaceRules[name] = value; + } + + QString expandCode() const; + + QString name() const + { + return m_name; + } + +private: + const QString m_name; + QHash<QString, QString> replaceRules; +}; + +struct ReferenceCount +{ + enum Action { // 0x01 - 0xff + Invalid = 0x00, + Add = 0x01, + AddAll = 0x02, + Remove = 0x04, + Set = 0x08, + Ignore = 0x10, + + ActionsMask = 0xff, + + Padding = 0xffffffff + }; + + QString varName; + Action action = Invalid; +}; + +struct ArgumentOwner +{ + enum Action { + Invalid = 0x00, + Add = 0x01, + Remove = 0x02 + }; + enum { + InvalidIndex = -2, + ThisIndex = -1, + ReturnIndex = 0, + FirstArgumentIndex = 1 + }; + + Action action = Invalid; + int index = InvalidIndex; +}; + +class CodeSnipFragment +{ +public: + CodeSnipFragment() = default; + explicit CodeSnipFragment(const QString &code) : m_code(code) {} + explicit CodeSnipFragment(TemplateInstance *instance) : m_instance(instance) {} + + QString code() const; + +private: + QString m_code; + TemplateInstance *m_instance = nullptr; +}; + +class CodeSnipAbstract +{ +public: + QString code() const; + + void addCode(const QString &code); + void addCode(QStringView code) { addCode(code.toString()); } + + void addTemplateInstance(TemplateInstance *ti) + { + codeList.append(CodeSnipFragment(ti)); + } + + QList<CodeSnipFragment> codeList; + + static QString fixSpaces(QString code); + static QString dedent(const QString &code); + static void prependCode(QString *code, QString firstLine); +}; + +class CustomFunction : public CodeSnipAbstract +{ +public: + explicit CustomFunction(const QString &n = QString()) : name(n) {} + + QString name; + QString paramName; +}; + +class TemplateEntry : public CodeSnipAbstract +{ +public: + explicit TemplateEntry(const QString &name) : m_name(name) {} + + QString name() const + { + return m_name; + } + +private: + QString m_name; +}; + +class CodeSnip : public CodeSnipAbstract +{ +public: + CodeSnip() = default; + explicit CodeSnip(TypeSystem::Language lang) : language(lang) {} + + TypeSystem::Language language = TypeSystem::TargetLangCode; + TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny; + ArgumentMap argumentMap; +}; + +struct ArgumentModification +{ + ArgumentModification() : removedDefaultExpression(false), removed(false), + noNullPointers(false), resetAfterUse(false), array(false) {} + explicit ArgumentModification(int idx) : index(idx), removedDefaultExpression(false), removed(false), + noNullPointers(false), resetAfterUse(false), array(false) {} + + // Should the default expression be removed? + + + // Reference count flags for this argument + QList<ReferenceCount> referenceCounts; + + // The text given for the new type of the argument + QString modified_type; + + QString replace_value; + + // The text of the new default expression of the argument + QString replacedDefaultExpression; + + // The new definition of ownership for a specific argument + QHash<TypeSystem::Language, TypeSystem::Ownership> ownerships; + + // Different conversion rules + CodeSnipList conversion_rules; + + //QObject parent(owner) of this argument + ArgumentOwner owner; + + //New name + QString renamed_to; + + // The index of this argument + int index = -1; + + uint removedDefaultExpression : 1; + uint removed : 1; + uint noNullPointers : 1; + uint resetAfterUse : 1; + uint array : 1; // consider "int*" to be "int[]" +}; + +struct Modification +{ + enum ModifierFlag { + InvalidModifier = 0x0000, + Private = 0x0001, + Protected = 0x0002, + Public = 0x0003, + Friendly = 0x0004, + AccessModifierMask = 0x000f, + + Final = 0x0010, + NonFinal = 0x0020, + FinalMask = Final | NonFinal, + + Readable = 0x0100, + Writable = 0x0200, + + CodeInjection = 0x1000, + Rename = 0x2000, + Deprecated = 0x4000, + ReplaceExpression = 0x8000 + }; + + Q_DECLARE_FLAGS(Modifiers, ModifierFlag); + + bool isAccessModifier() const + { + return (modifiers & AccessModifierMask) != 0; + } + Modifiers accessModifier() const + { + return modifiers & AccessModifierMask; + } + bool isPrivate() const + { + return accessModifier() == Private; + } + bool isProtected() const + { + return accessModifier() == Protected; + } + bool isPublic() const + { + return accessModifier() == Public; + } + bool isFriendly() const + { + return accessModifier() == Friendly; + } + bool isFinal() const + { + return modifiers.testFlag(Final); + } + bool isNonFinal() const + { + return modifiers.testFlag(NonFinal); + } + QString accessModifierString() const; + + bool isDeprecated() const + { + return modifiers.testFlag(Deprecated); + } + + void setRenamedTo(const QString &name) + { + renamedToName = name; + } + QString renamedTo() const + { + return renamedToName; + } + bool isRenameModifier() const + { + return modifiers.testFlag(Rename); + } + + bool isRemoveModifier() const + { + return removal != TypeSystem::NoLanguage; + } + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const; +#endif + + QString renamedToName; + Modifiers modifiers; + TypeSystem::Language removal = TypeSystem::NoLanguage; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(Modification::Modifiers) + +struct FunctionModification: public Modification +{ + using AllowThread = TypeSystem::AllowThread; + + bool isCodeInjection() const + { + return modifiers.testFlag(CodeInjection); + } + void setIsThread(bool flag) + { + m_thread = flag; + } + bool isThread() const + { + return m_thread; + } + + AllowThread allowThread() const { return m_allowThread; } + void setAllowThread(AllowThread allow) { m_allowThread = allow; } + + bool matches(const QString &functionSignature) const + { + return m_signature.isEmpty() + ? m_signaturePattern.match(functionSignature).hasMatch() + : m_signature == functionSignature; + } + + bool setSignature(const QString &s, QString *errorMessage = nullptr); + QString signature() const { return m_signature.isEmpty() ? m_signaturePattern.pattern() : m_signature; } + + void setOriginalSignature(const QString &s) { m_originalSignature = s; } + QString originalSignature() const { return m_originalSignature; } + + TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; } + void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; } + + int overloadNumber() const { return m_overloadNumber; } + void setOverloadNumber(int overloadNumber) { m_overloadNumber = overloadNumber; } + +#ifndef QT_NO_DEBUG_STREAM + void formatDebug(QDebug &d) const; +#endif + + QString association; + CodeSnipList snips; + + QList<ArgumentModification> argument_mods; + +private: + QString m_signature; + QString m_originalSignature; + QRegularExpression m_signaturePattern; + int m_overloadNumber = TypeSystem::OverloadNumberUnset; + bool m_thread = false; + AllowThread m_allowThread = AllowThread::Unspecified; + TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const ReferenceCount &); +QDebug operator<<(QDebug d, const ArgumentOwner &a); +QDebug operator<<(QDebug d, const ArgumentModification &a); +QDebug operator<<(QDebug d, const FunctionModification &fm); +#endif + +struct FieldModification: public Modification +{ + bool isReadable() const + { + return modifiers.testFlag(Readable); + } + bool isWritable() const + { + return modifiers.testFlag(Writable); + } + + QString name; +}; + +/** +* \internal +* Struct used to store information about functions added by the typesystem. +* This info will be used later to create a fake AbstractMetaFunction which +* will be inserted into the right AbstractMetaClass. +*/ +struct AddedFunction +{ + /// Function access types. + enum Access { + InvalidAccess = 0, + Protected = 0x1, + Public = 0x2 + }; + + /** + * \internal + * Internal struct used to store information about arguments and return type of the + * functions added by the type system. This information is later used to create + * AbstractMetaType and AbstractMetaArgument for the AbstractMetaFunctions. + */ + struct TypeInfo { + TypeInfo() = default; + static TypeInfo fromSignature(const QString& signature); + + QString name; + int indirections = 0; + bool isConstant = false; + bool isReference = false; + }; + + struct Argument + { + TypeInfo typeInfo; + QString name; + QString defaultValue; + }; + + /// Creates a new AddedFunction with a signature and a return type. + explicit AddedFunction(QString signature, const QString &returnType); + AddedFunction() = default; + + /// Returns the function name. + QString name() const + { + return m_name; + } + + /// Set the function access type. + void setAccess(Access access) + { + m_access = access; + } + + /// Returns the function access type. + Access access() const + { + return m_access; + } + + /// Returns the function return type. + TypeInfo returnType() const + { + return m_returnType; + } + + /// Returns a list of argument type infos. + const QList<Argument> &arguments() const + { + return m_arguments; + } + + /// Returns true if this is a constant method. + bool isConstant() const + { + return m_isConst; + } + + /// Set this method static. + void setStatic(bool value) + { + m_isStatic = value; + } + + /// Returns true if this is a static method. + bool isStatic() const + { + return m_isStatic; + } + + bool isDeclaration() const { return m_isDeclaration; } // <declare-function> + void setDeclaration(bool value) { m_isDeclaration = value; } + + FunctionModificationList modifications; + +private: + QString m_name; + QList<Argument> m_arguments; + TypeInfo m_returnType; + Access m_access = Protected; + bool m_isConst = false; + bool m_isStatic = false; + bool m_isDeclaration = false; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti); +QDebug operator<<(QDebug d, const AddedFunction::Argument &a); +QDebug operator<<(QDebug d, const AddedFunction &af); +#endif + +class DocModification +{ +public: + DocModification() = default; + explicit DocModification(const QString& xpath, const QString& signature) : + m_xpath(xpath), m_signature(signature) {} + explicit DocModification(TypeSystem::DocModificationMode mode, const QString& signature) : + m_signature(signature), m_mode(mode) {} + + void setCode(const QString& code); + void setCode(QStringView code) { setCode(code.toString()); } + + QString code() const + { + return m_code; + } + QString xpath() const + { + return m_xpath; + } + QString signature() const + { + return m_signature; + } + TypeSystem::DocModificationMode mode() const + { + return m_mode; + } + + TypeSystem::Language format() const { return m_format; } + void setFormat(TypeSystem::Language f) { m_format = f; } + +private: + QString m_code; + QString m_xpath; + QString m_signature; + TypeSystem::DocModificationMode m_mode = TypeSystem::DocModificationXPathReplace; + TypeSystem::Language m_format = TypeSystem::NativeCode; +}; + +#endif // MODIFICATIONS_H diff --git a/sources/shiboken6/ApiExtractor/typesystem.cpp b/sources/shiboken6/ApiExtractor/typesystem.cpp index b13f26464..a7a042c62 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.cpp +++ b/sources/shiboken6/ApiExtractor/typesystem.cpp @@ -33,9 +33,6 @@ #include <QtCore/QRegularExpression> #include <QtCore/QSet> -#include <algorithm> -#include <limits> - static QString strings_Object = QLatin1String("Object"); static QString strings_String = QLatin1String("String"); static QString strings_char = QLatin1String("char"); @@ -83,15 +80,6 @@ void TypeEntry::addExtraInclude(const Include &newInclude) m_extraIncludes.append(newInclude); } -QString Modification::accessModifierString() const -{ - if (isPrivate()) return QLatin1String("private"); - if (isProtected()) return QLatin1String("protected"); - if (isPublic()) return QLatin1String("public"); - if (isFriendly()) return QLatin1String("friendly"); - return QString(); -} - FunctionModificationList ComplexTypeEntry::functionModifications(const QString &signature) const { FunctionModificationList lst; @@ -198,454 +186,6 @@ TypeEntry *FlagsTypeEntry::clone() const FlagsTypeEntry::FlagsTypeEntry(const FlagsTypeEntry &) = default; -QString TemplateInstance::expandCode() const -{ - TemplateEntry *templateEntry = TypeDatabase::instance()->findTemplate(m_name); - if (!templateEntry) - qFatal("<insert-template> referring to non-existing template '%s'.", qPrintable(m_name)); - - QString code = templateEntry->code(); - for (auto it = replaceRules.cbegin(), end = replaceRules.cend(); it != end; ++it) - code.replace(it.key(), it.value()); - while (!code.isEmpty() && code.at(code.size() - 1).isSpace()) - code.chop(1); - QString result = QLatin1String("// TEMPLATE - ") + m_name + QLatin1String(" - START"); - if (!code.startsWith(QLatin1Char('\n'))) - result += QLatin1Char('\n'); - result += code; - result += QLatin1String("\n// TEMPLATE - ") + m_name + QLatin1String(" - END\n"); - return result; -} - - -QString CodeSnipAbstract::code() const -{ - QString res; - for (const CodeSnipFragment &codeFrag : codeList) - res.append(codeFrag.code()); - - return res; -} - -void CodeSnipAbstract::addCode(const QString &code) -{ - codeList.append(CodeSnipFragment(fixSpaces(code))); -} - -static inline int firstNonBlank(QStringView s) -{ - const auto it = std::find_if(s.cbegin(), s.cend(), - [] (QChar c) { return !c.isSpace(); }); - return int(it - s.cbegin()); -} - -static inline bool isEmpty(QStringView s) -{ - return s.isEmpty() - || std::all_of(s.cbegin(), s.cend(), - [] (QChar c) { return c.isSpace(); }); -} - -QString CodeSnipAbstract::dedent(const QString &code) -{ - if (code.isEmpty()) - return code; - // Right trim if indent=0, or trim if single line - if (!code.at(0).isSpace() || !code.contains(QLatin1Char('\n'))) - return code.trimmed(); - const auto lines = QStringView{code}.split(QLatin1Char('\n')); - int spacesToRemove = std::numeric_limits<int>::max(); - for (const auto &line : lines) { - if (!isEmpty(line)) { - const int nonSpacePos = firstNonBlank(line); - if (nonSpacePos < spacesToRemove) - spacesToRemove = nonSpacePos; - if (spacesToRemove == 0) - return code; - } - } - QString result; - for (const auto &line : lines) { - if (!isEmpty(line) && spacesToRemove < line.size()) - result += line.mid(spacesToRemove).toString(); - result += QLatin1Char('\n'); - } - return result; -} - -QString CodeSnipAbstract::fixSpaces(QString code) -{ - code.remove(QLatin1Char('\r')); - // Check for XML <tag>\n<space>bla... - if (code.startsWith(QLatin1String("\n "))) - code.remove(0, 1); - while (!code.isEmpty() && code.back().isSpace()) - code.chop(1); - code = dedent(code); - if (!code.isEmpty() && !code.endsWith(QLatin1Char('\n'))) - code.append(QLatin1Char('\n')); - return code; -} - -// Prepend a line to the code, observing indentation -void CodeSnipAbstract::prependCode(QString *code, QString firstLine) -{ - while (!code->isEmpty() && code->front() == QLatin1Char('\n')) - code->remove(0, 1); - if (!code->isEmpty() && code->front().isSpace()) { - const int indent = firstNonBlank(*code); - firstLine.prepend(QString(indent, QLatin1Char(' '))); - } - if (!firstLine.endsWith(QLatin1Char('\n'))) - firstLine += QLatin1Char('\n'); - code->prepend(firstLine); -} - -QString CodeSnipFragment::code() const -{ - return m_instance ? m_instance->expandCode() : m_code; -} - -bool FunctionModification::setSignature(const QString &s, QString *errorMessage) -{ - if (s.startsWith(QLatin1Char('^'))) { - m_signaturePattern.setPattern(s); - if (!m_signaturePattern.isValid()) { - if (errorMessage) { - *errorMessage = QLatin1String("Invalid signature pattern: \"") - + s + QLatin1String("\": ") + m_signaturePattern.errorString(); - } - return false; - } - } else { - m_signature = s; - } - return true; -} - -QString FunctionModification::toString() const -{ - QString str = signature() + QLatin1String("->"); - if (modifiers & AccessModifierMask) { - switch (modifiers & AccessModifierMask) { - case Private: str += QLatin1String("private"); break; - case Protected: str += QLatin1String("protected"); break; - case Public: str += QLatin1String("public"); break; - case Friendly: str += QLatin1String("friendly"); break; - } - } - - if (modifiers & Final) str += QLatin1String("final"); - if (modifiers & NonFinal) str += QLatin1String("non-final"); - - if (modifiers & Readable) str += QLatin1String("readable"); - if (modifiers & Writable) str += QLatin1String("writable"); - - if (modifiers & CodeInjection) { - for (const CodeSnip &s : snips) { - str += QLatin1String("\n//code injection:\n"); - str += s.code(); - } - } - - if (modifiers & Rename) str += QLatin1String("renamed:") + renamedToName; - - if (modifiers & Deprecated) str += QLatin1String("deprecate"); - - if (modifiers & ReplaceExpression) str += QLatin1String("replace-expression"); - - return str; -} - -static AddedFunction::TypeInfo parseType(const QString& signature, - int startPos = 0, int *endPos = nullptr, - QString *argumentName = nullptr, - QString *defaultValue = nullptr) -{ - AddedFunction::TypeInfo result; - static const QRegularExpression regex(QLatin1String("\\w")); - Q_ASSERT(regex.isValid()); - int length = signature.length(); - int start = signature.indexOf(regex, startPos); - if (start == -1) { - if (QStringView{signature}.mid(startPos + 1, 3) == QLatin1String("...")) { // varargs - if (endPos) - *endPos = startPos + 4; - result.name = QLatin1String("..."); - } else { // error - if (endPos) - *endPos = length; - } - return result; - } - - int cantStop = 0; - QString paramString; - QChar c; - int i = start; - for (; i < length; ++i) { - c = signature[i]; - if (c == QLatin1Char('<')) - cantStop++; - if (c == QLatin1Char('>')) - cantStop--; - if (cantStop < 0) - break; // FIXME: report error? - if ((c == QLatin1Char(')') || c == QLatin1Char(',')) && !cantStop) - break; - paramString += signature[i]; - } - if (endPos) - *endPos = i; - - // Check default value - if (paramString.contains(QLatin1Char('='))) { - QStringList lst = paramString.split(QLatin1Char('=')); - paramString = lst[0].trimmed(); - if (defaultValue != nullptr) - *defaultValue = lst[1].trimmed(); - } - - // check constness - if (paramString.startsWith(QLatin1String("const "))) { - result.isConstant = true; - paramString.remove(0, sizeof("const")/sizeof(char)); - paramString = paramString.trimmed(); - } - - // Extract argument name from "T<bla,blub>* @foo@" - const int nameStartPos = paramString.indexOf(QLatin1Char('@')); - if (nameStartPos != -1) { - const int nameEndPos = paramString.indexOf(QLatin1Char('@'), nameStartPos + 1); - if (nameEndPos > nameStartPos) { - if (argumentName) - *argumentName = paramString.mid(nameStartPos + 1, nameEndPos - nameStartPos - 1); - paramString.remove(nameStartPos, nameEndPos - nameStartPos + 1); - paramString = paramString.trimmed(); - } - } - - // check reference - if (paramString.endsWith(QLatin1Char('&'))) { - result.isReference = true; - paramString.chop(1); - paramString = paramString.trimmed(); - } - // check Indirections - while (paramString.endsWith(QLatin1Char('*'))) { - result.indirections++; - paramString.chop(1); - paramString = paramString.trimmed(); - } - result.name = paramString; - - return result; -} - -AddedFunction::AddedFunction(QString signature, const QString &returnType) : - m_access(Public) -{ - Q_ASSERT(!returnType.isEmpty()); - m_returnType = parseType(returnType); - signature = signature.trimmed(); - // Skip past "operator()(...)" - const int parenStartPos = signature.startsWith(callOperator()) - ? callOperator().size() : 0; - int endPos = signature.indexOf(QLatin1Char('('), parenStartPos); - if (endPos < 0) { - m_isConst = false; - m_name = signature; - } else { - m_name = signature.left(endPos).trimmed(); - int signatureLength = signature.length(); - while (endPos < signatureLength) { - QString argumentName; - QString defaultValue; - TypeInfo arg = parseType(signature, endPos, &endPos, &argumentName, &defaultValue); - if (!arg.name.isEmpty()) - m_arguments.append({arg, argumentName, defaultValue}); - // end of parameters... - if (endPos >= signatureLength || signature[endPos] == QLatin1Char(')')) - break; - } - // is const? - m_isConst = QStringView{signature}.right(signatureLength - endPos).contains(QLatin1String("const")); - } -} - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const ReferenceCount &r) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "ReferenceCount(" << r.varName << ", action=" << r.action << ')'; - return d; -} - -QDebug operator<<(QDebug d, const CodeSnip &s) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "CodeSnip(language=" << s.language << ", position=" << s.position << ", \""; - for (const auto &f : s.codeList) { - const QString &code = f.code(); - const auto lines = QStringView{code}.split(QLatin1Char('\n')); - for (int i = 0, size = lines.size(); i < size; ++i) { - if (i) - d << "\\n"; - d << lines.at(i).trimmed(); - } - } - d << '"'; - if (!s.argumentMap.isEmpty()) { - d << ", argumentMap{"; - for (auto it = s.argumentMap.cbegin(), end = s.argumentMap.cend(); it != end; ++it) - d << it.key() << "->\"" << it.value() << '"'; - d << '}'; - } - d << ')'; - return d; -} - -void Modification::formatDebug(QDebug &d) const -{ - d << "modifiers=" << Qt::hex << Qt::showbase << modifiers << Qt::noshowbase << Qt::dec; - if (removal) - d << ", removal"; - if (!renamedToName.isEmpty()) - d << ", renamedToName=\"" << renamedToName << '"'; -} - -void FunctionModification::formatDebug(QDebug &d) const -{ - if (m_signature.isEmpty()) - d << "pattern=\"" << m_signaturePattern.pattern(); - else - d << "signature=\"" << m_signature; - d << "\", "; - Modification::formatDebug(d); - if (!association.isEmpty()) - d << ", association=\"" << association << '"'; - if (m_allowThread != TypeSystem::AllowThread::Unspecified) - d << ", allowThread=" << int(m_allowThread); - if (m_thread) - d << ", thread"; - if (m_exceptionHandling != TypeSystem::ExceptionHandling::Unspecified) - d << ", exceptionHandling=" << int(m_exceptionHandling); - if (!snips.isEmpty()) - d << ", snips=(" << snips << ')'; - if (!argument_mods.isEmpty()) - d << ", argument_mods=(" << argument_mods << ')'; -} - -QDebug operator<<(QDebug d, const ArgumentOwner &a) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "ArgumentOwner(index=" << a.index << ", action=" << a.action << ')'; - return d; -} - -QDebug operator<<(QDebug d, const ArgumentModification &a) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "ArgumentModification(index=" << a.index; - if (a.removedDefaultExpression) - d << ", removedDefaultExpression"; - if (a.removed) - d << ", removed"; - if (a.noNullPointers) - d << ", noNullPointers"; - if (a.array) - d << ", array"; - if (!a.referenceCounts.isEmpty()) - d << ", referenceCounts=" << a.referenceCounts; - if (!a.modified_type.isEmpty()) - d << ", modified_type=\"" << a.modified_type << '"'; - if (!a.replace_value.isEmpty()) - d << ", replace_value=\"" << a.replace_value << '"'; - if (!a.replacedDefaultExpression.isEmpty()) - d << ", replacedDefaultExpression=\"" << a.replacedDefaultExpression << '"'; - if (!a.ownerships.isEmpty()) - d << ", ownerships=" << a.ownerships; - if (!a.renamed_to.isEmpty()) - d << ", renamed_to=\"" << a.renamed_to << '"'; - d << ", owner=" << a.owner << ')'; - return d; -} - -QDebug operator<<(QDebug d, const FunctionModification &fm) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "FunctionModification("; - fm.formatDebug(d); - d << ')'; - return d; -} - -QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "TypeInfo("; - if (ti.isConstant) - d << "const"; - if (ti.indirections) - d << QByteArray(ti.indirections, '*'); - if (ti.isReference) - d << " &"; - d << ti.name; - d << ')'; - return d; -} - -QDebug operator<<(QDebug d, const AddedFunction::Argument &a) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "Argument("; - d << a.typeInfo; - if (!a.name.isEmpty()) - d << ' ' << a.name; - if (!a.defaultValue.isEmpty()) - d << " = " << a.defaultValue; - d << ')'; - return d; -} - -QDebug operator<<(QDebug d, const AddedFunction &af) -{ - QDebugStateSaver saver(d); - d.noquote(); - d.nospace(); - d << "AddedFunction("; - if (af.access() == AddedFunction::Protected) - d << "protected"; - if (af.isStatic()) - d << " static"; - d << af.returnType() << ' ' << af.name() << '(' << af.arguments() << ')'; - if (af.isConstant()) - d << " const"; - if (af.isDeclaration()) - d << " [declaration]"; - return d; -} -#endif // !QT_NO_DEBUG_STREAM - -AddedFunction::TypeInfo AddedFunction::TypeInfo::fromSignature(const QString& signature) -{ - return parseType(signature); -} - static QString buildName(const QString &entryName, const TypeEntry *parent) { return parent == nullptr || parent->type() == TypeEntry::TypeSystemType @@ -1274,8 +814,3 @@ TypeEntry *ObjectTypeEntry::clone() const } ObjectTypeEntry::ObjectTypeEntry(const ObjectTypeEntry &) = default; - -void DocModification::setCode(const QString &code) -{ - m_code = CodeSnipAbstract::fixSpaces(code); -} diff --git a/sources/shiboken6/ApiExtractor/typesystem.h b/sources/shiboken6/ApiExtractor/typesystem.h index 1a401558a..561969542 100644 --- a/sources/shiboken6/ApiExtractor/typesystem.h +++ b/sources/shiboken6/ApiExtractor/typesystem.h @@ -31,6 +31,7 @@ #include "typesystem_enums.h" #include "typesystem_typedefs.h" +#include "modifications.h" #include "include.h" #include "sourcelocation.h" @@ -47,516 +48,15 @@ extern const char *TARGET_CONVERSION_RULE_FLAG; extern const char *NATIVE_CONVERSION_RULE_FLAG; -class AbstractMetaType; +class CustomConversion; +class FlagsTypeEntry; +class TypeSystemTypeEntry; + QT_BEGIN_NAMESPACE class QDebug; class QTextStream; QT_END_NAMESPACE -class EnumTypeEntry; -class FlagsTypeEntry; - -using ArgumentMap = QMap<int, QString>; - -class TemplateInstance; - -struct ReferenceCount -{ - enum Action { // 0x01 - 0xff - Invalid = 0x00, - Add = 0x01, - AddAll = 0x02, - Remove = 0x04, - Set = 0x08, - Ignore = 0x10, - - ActionsMask = 0xff, - - Padding = 0xffffffff - }; - - QString varName; - Action action = Invalid; -}; - -struct ArgumentOwner -{ - enum Action { - Invalid = 0x00, - Add = 0x01, - Remove = 0x02 - }; - enum { - InvalidIndex = -2, - ThisIndex = -1, - ReturnIndex = 0, - FirstArgumentIndex = 1 - }; - - Action action = Invalid; - int index = InvalidIndex; -}; - -class CodeSnipFragment -{ -public: - CodeSnipFragment() = default; - explicit CodeSnipFragment(const QString &code) : m_code(code) {} - explicit CodeSnipFragment(TemplateInstance *instance) : m_instance(instance) {} - - QString code() const; - -private: - QString m_code; - TemplateInstance *m_instance = nullptr; -}; - -class CodeSnipAbstract -{ -public: - QString code() const; - - void addCode(const QString &code); - void addCode(QStringView code) { addCode(code.toString()); } - - void addTemplateInstance(TemplateInstance *ti) - { - codeList.append(CodeSnipFragment(ti)); - } - - QVector<CodeSnipFragment> codeList; - - static QString fixSpaces(QString code); - static QString dedent(const QString &code); - static void prependCode(QString *code, QString firstLine); -}; - -class CustomFunction : public CodeSnipAbstract -{ -public: - explicit CustomFunction(const QString &n = QString()) : name(n) {} - - QString name; - QString paramName; -}; - -class TemplateEntry : public CodeSnipAbstract -{ -public: - explicit TemplateEntry(const QString &name) : m_name(name) {} - - QString name() const - { - return m_name; - } - -private: - QString m_name; -}; - -class TemplateInstance -{ -public: - explicit TemplateInstance(const QString &name) : m_name(name) {} - - void addReplaceRule(const QString &name, const QString &value) - { - replaceRules[name] = value; - } - - QString expandCode() const; - - QString name() const - { - return m_name; - } - -private: - const QString m_name; - QHash<QString, QString> replaceRules; -}; - - -class CodeSnip : public CodeSnipAbstract -{ -public: - CodeSnip() = default; - explicit CodeSnip(TypeSystem::Language lang) : language(lang) {} - - TypeSystem::Language language = TypeSystem::TargetLangCode; - TypeSystem::CodeSnipPosition position = TypeSystem::CodeSnipPositionAny; - ArgumentMap argumentMap; -}; - -struct ArgumentModification -{ - ArgumentModification() : removedDefaultExpression(false), removed(false), - noNullPointers(false), resetAfterUse(false), array(false) {} - explicit ArgumentModification(int idx) : index(idx), removedDefaultExpression(false), removed(false), - noNullPointers(false), resetAfterUse(false), array(false) {} - - // Should the default expression be removed? - - - // Reference count flags for this argument - QVector<ReferenceCount> referenceCounts; - - // The text given for the new type of the argument - QString modified_type; - - QString replace_value; - - // The text of the new default expression of the argument - QString replacedDefaultExpression; - - // The new definition of ownership for a specific argument - QHash<TypeSystem::Language, TypeSystem::Ownership> ownerships; - - // Different conversion rules - CodeSnipList conversion_rules; - - //QObject parent(owner) of this argument - ArgumentOwner owner; - - //New name - QString renamed_to; - - // The index of this argument - int index = -1; - - uint removedDefaultExpression : 1; - uint removed : 1; - uint noNullPointers : 1; - uint resetAfterUse : 1; - uint array : 1; // consider "int*" to be "int[]" -}; - -struct Modification -{ - enum Modifiers : uint { - InvalidModifier = 0x0000, - Private = 0x0001, - Protected = 0x0002, - Public = 0x0003, - Friendly = 0x0004, - AccessModifierMask = 0x000f, - - Final = 0x0010, - NonFinal = 0x0020, - FinalMask = Final | NonFinal, - - Readable = 0x0100, - Writable = 0x0200, - - CodeInjection = 0x1000, - Rename = 0x2000, - Deprecated = 0x4000, - ReplaceExpression = 0x8000 - }; - - bool isAccessModifier() const - { - return modifiers & AccessModifierMask; - } - Modifiers accessModifier() const - { - return Modifiers(modifiers & AccessModifierMask); - } - bool isPrivate() const - { - return accessModifier() == Private; - } - bool isProtected() const - { - return accessModifier() == Protected; - } - bool isPublic() const - { - return accessModifier() == Public; - } - bool isFriendly() const - { - return accessModifier() == Friendly; - } - bool isFinal() const - { - return modifiers & Final; - } - bool isNonFinal() const - { - return modifiers & NonFinal; - } - QString accessModifierString() const; - - bool isDeprecated() const - { - return modifiers & Deprecated; - } - - void setRenamedTo(const QString &name) - { - renamedToName = name; - } - QString renamedTo() const - { - return renamedToName; - } - bool isRenameModifier() const - { - return modifiers & Rename; - } - - bool isRemoveModifier() const - { - return removal != TypeSystem::NoLanguage; - } - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const; -#endif - - QString renamedToName; - uint modifiers = 0; - TypeSystem::Language removal = TypeSystem::NoLanguage; -}; - -struct FunctionModification: public Modification -{ - using AllowThread = TypeSystem::AllowThread; - - bool isCodeInjection() const - { - return modifiers & CodeInjection; - } - void setIsThread(bool flag) - { - m_thread = flag; - } - bool isThread() const - { - return m_thread; - } - - AllowThread allowThread() const { return m_allowThread; } - void setAllowThread(AllowThread allow) { m_allowThread = allow; } - - bool matches(const QString &functionSignature) const - { - return m_signature.isEmpty() - ? m_signaturePattern.match(functionSignature).hasMatch() - : m_signature == functionSignature; - } - - bool setSignature(const QString &s, QString *errorMessage = nullptr); - QString signature() const { return m_signature.isEmpty() ? m_signaturePattern.pattern() : m_signature; } - - void setOriginalSignature(const QString &s) { m_originalSignature = s; } - QString originalSignature() const { return m_originalSignature; } - - TypeSystem::ExceptionHandling exceptionHandling() const { return m_exceptionHandling; } - void setExceptionHandling(TypeSystem::ExceptionHandling e) { m_exceptionHandling = e; } - - int overloadNumber() const { return m_overloadNumber; } - void setOverloadNumber(int overloadNumber) { m_overloadNumber = overloadNumber; } - - QString toString() const; - -#ifndef QT_NO_DEBUG_STREAM - void formatDebug(QDebug &d) const; -#endif - - QString association; - CodeSnipList snips; - - QVector<ArgumentModification> argument_mods; - -private: - QString m_signature; - QString m_originalSignature; - QRegularExpression m_signaturePattern; - int m_overloadNumber = TypeSystem::OverloadNumberUnset; - bool m_thread = false; - AllowThread m_allowThread = AllowThread::Unspecified; - TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; -}; - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const ReferenceCount &); -QDebug operator<<(QDebug d, const ArgumentOwner &a); -QDebug operator<<(QDebug d, const ArgumentModification &a); -QDebug operator<<(QDebug d, const FunctionModification &fm); -#endif - -struct FieldModification: public Modification -{ - bool isReadable() const - { - return modifiers & Readable; - } - bool isWritable() const - { - return modifiers & Writable; - } - - QString name; -}; - -/** -* \internal -* Struct used to store information about functions added by the typesystem. -* This info will be used later to create a fake AbstractMetaFunction which -* will be inserted into the right AbstractMetaClass. -*/ -struct AddedFunction -{ - /// Function access types. - enum Access { - InvalidAccess = 0, - Protected = 0x1, - Public = 0x2 - }; - - /** - * \internal - * Internal struct used to store information about arguments and return type of the - * functions added by the type system. This information is later used to create - * AbstractMetaType and AbstractMetaArgument for the AbstractMetaFunctions. - */ - struct TypeInfo { - TypeInfo() = default; - static TypeInfo fromSignature(const QString& signature); - - QString name; - int indirections = 0; - bool isConstant = false; - bool isReference = false; - }; - - struct Argument - { - TypeInfo typeInfo; - QString name; - QString defaultValue; - }; - - /// Creates a new AddedFunction with a signature and a return type. - explicit AddedFunction(QString signature, const QString &returnType); - AddedFunction() = default; - - /// Returns the function name. - QString name() const - { - return m_name; - } - - /// Set the function access type. - void setAccess(Access access) - { - m_access = access; - } - - /// Returns the function access type. - Access access() const - { - return m_access; - } - - /// Returns the function return type. - TypeInfo returnType() const - { - return m_returnType; - } - - /// Returns a list of argument type infos. - const QVector<Argument> &arguments() const - { - return m_arguments; - } - - /// Returns true if this is a constant method. - bool isConstant() const - { - return m_isConst; - } - - /// Set this method static. - void setStatic(bool value) - { - m_isStatic = value; - } - - /// Returns true if this is a static method. - bool isStatic() const - { - return m_isStatic; - } - - bool isDeclaration() const { return m_isDeclaration; } // <declare-function> - void setDeclaration(bool value) { m_isDeclaration = value; } - - FunctionModificationList modifications; - -private: - QString m_name; - QVector<Argument> m_arguments; - TypeInfo m_returnType; - Access m_access = Protected; - bool m_isConst = false; - bool m_isStatic = false; - bool m_isDeclaration = false; -}; - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug d, const AddedFunction::TypeInfo &ti); -QDebug operator<<(QDebug d, const AddedFunction::Argument &a); -QDebug operator<<(QDebug d, const AddedFunction &af); -#endif - -class ObjectTypeEntry; - -class DocModification -{ -public: - DocModification() = default; - explicit DocModification(const QString& xpath, const QString& signature) : - m_xpath(xpath), m_signature(signature) {} - explicit DocModification(TypeSystem::DocModificationMode mode, const QString& signature) : - m_signature(signature), m_mode(mode) {} - - void setCode(const QString& code); - void setCode(QStringView code) { setCode(code.toString()); } - - QString code() const - { - return m_code; - } - QString xpath() const - { - return m_xpath; - } - QString signature() const - { - return m_signature; - } - TypeSystem::DocModificationMode mode() const - { - return m_mode; - } - - TypeSystem::Language format() const { return m_format; } - void setFormat(TypeSystem::Language f) { m_format = f; } - -private: - QString m_code; - QString m_xpath; - QString m_signature; - TypeSystem::DocModificationMode m_mode = TypeSystem::DocModificationXPathReplace; - TypeSystem::Language m_format = TypeSystem::NativeCode; -}; - -class CustomConversion; -class TypeSystemTypeEntry; - struct TypeSystemProperty { bool isValid() const { return !name.isEmpty() && !read.isEmpty() && !type.isEmpty(); } |