// Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "modifications.h" #include "codesnip.h" #include "qtcompat.h" #include #include #include #include using namespace Qt::StringLiterals; // ---------------------- FieldModification class FieldModificationData : public QSharedData { public: QString m_name; QString m_renamedToName; bool m_readable = true; bool m_writable = true; bool m_removed = false; bool m_opaqueContainer = false; TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified; }; FieldModification::FieldModification() : d(new FieldModificationData) { } FieldModification::FieldModification(const FieldModification &) = default; FieldModification &FieldModification::operator=(const FieldModification &) = default; FieldModification::FieldModification(FieldModification &&) noexcept = default; FieldModification &FieldModification::operator=(FieldModification &&) noexcept = default; FieldModification::~FieldModification() = default; QString FieldModification::name() const { return d->m_name; } void FieldModification::setName(const QString &value) { if (d->m_name != value) d->m_name = value; } bool FieldModification::isRenameModifier() const { return !d->m_renamedToName.isEmpty(); } QString FieldModification::renamedToName() const { return d->m_renamedToName; } void FieldModification::setRenamedToName(const QString &value) { if (d->m_renamedToName != value) d->m_renamedToName = value; } bool FieldModification::isReadable() const { return d->m_readable; } void FieldModification::setReadable(bool e) { if (d->m_readable != e) d->m_readable = e; } bool FieldModification::isWritable() const { return d->m_writable; } void FieldModification::setWritable(bool e) { if (d->m_writable != e) d->m_writable = e; } bool FieldModification::isRemoved() const { return d->m_removed; } void FieldModification::setRemoved(bool r) { if (d->m_removed != r) d->m_removed = r; } bool FieldModification::isOpaqueContainer() const { return d->m_opaqueContainer; } void FieldModification::setOpaqueContainer(bool r) { if (d->m_opaqueContainer != r) d->m_opaqueContainer = r; } TypeSystem::SnakeCase FieldModification::snakeCase() const { return d->snakeCase; } void FieldModification::setSnakeCase(TypeSystem::SnakeCase s) { if (d->snakeCase != s) d->snakeCase = s; } // Remove the parameter names enclosed in '@' from an added function signature // so that it matches the C++ type signature. static QString removeParameterNames(QString signature) { while (true) { const auto ampPos = signature.indexOf(u'@'); if (ampPos == -1) break; const auto closingAmpPos = signature.indexOf(u'@', ampPos + 1); if (closingAmpPos == -1) break; signature.remove(ampPos, closingAmpPos - ampPos + 1); } return signature; } DocModification::DocModification(const QString &xpath, const QString &signature) : m_xpath(xpath), m_signature(removeParameterNames(signature)) { } DocModification::DocModification(TypeSystem::DocModificationMode mode, const QString &signature) : m_signature(removeParameterNames(signature)), m_mode(mode) { } 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(); const auto &fragments = s.codeList(); const auto size = fragments.size(); d << "CodeSnip(language=" << s.language << ", position=" << s.position << ", fragments[" << size << "]="; for (qsizetype i = 0; i < size; ++i) { if (i) d << ", "; d << '#' << i << ' ' << fragments.at(i); } d << ')'; return d; } class ArgumentModificationData : public QSharedData { public: ArgumentModificationData(int idx = -1) : index(idx), removedDefaultExpression(false), removed(false), noNullPointers(false), resetAfterUse(false), array(false) {} bool equals(const ArgumentModificationData &rhs) const noexcept; size_t hash(size_t seed) const noexcept; QList referenceCounts; QString modified_type; QString pyiType; QString replacedDefaultExpression; TypeSystem::Ownership m_targetOwnerShip = TypeSystem::UnspecifiedOwnership; TypeSystem::Ownership m_nativeOwnerShip = TypeSystem::UnspecifiedOwnership; CodeSnipList conversion_rules; ArgumentOwner owner; QString renamed_to; int index = -1; uint removedDefaultExpression : 1; uint removed : 1; uint noNullPointers : 1; uint resetAfterUse : 1; uint array : 1; }; bool ArgumentModificationData::equals(const ArgumentModificationData &rhs) const noexcept { return referenceCounts == rhs.referenceCounts && modified_type == rhs.modified_type && pyiType == rhs.pyiType && replacedDefaultExpression == rhs.replacedDefaultExpression && m_targetOwnerShip == rhs.m_targetOwnerShip && m_nativeOwnerShip == rhs.m_nativeOwnerShip && conversion_rules == rhs.conversion_rules && owner == rhs.owner && renamed_to == rhs.renamed_to && index == rhs.index && removedDefaultExpression == rhs.removedDefaultExpression && removed == rhs.removedDefaultExpression && noNullPointers == rhs.noNullPointers && resetAfterUse == rhs.resetAfterUse && array == rhs.array; } size_t ArgumentModificationData::hash(size_t seed) const noexcept { return qHashMulti(seed, referenceCounts, modified_type, pyiType,replacedDefaultExpression, m_targetOwnerShip, m_nativeOwnerShip, conversion_rules, owner, renamed_to, index, removedDefaultExpression, removed, noNullPointers, resetAfterUse, array); } ArgumentModification::ArgumentModification() : d(new ArgumentModificationData) { } ArgumentModification::ArgumentModification(int idx) : d(new ArgumentModificationData(idx)) { } ArgumentModification::ArgumentModification(const ArgumentModification &) = default; ArgumentModification &ArgumentModification::operator=(const ArgumentModification &) = default; ArgumentModification::ArgumentModification(ArgumentModification &&) noexcept = default; ArgumentModification &ArgumentModification::operator=(ArgumentModification &&) noexcept = default; ArgumentModification::~ArgumentModification() = default; const QString &ArgumentModification::modifiedType() const { return d->modified_type; } void ArgumentModification::setModifiedType(const QString &value) { if (d->modified_type != value) d->modified_type = value; } bool ArgumentModification::isTypeModified() const { return !d->modified_type.isEmpty(); } QString ArgumentModification::pyiType() const { return d->pyiType; } void ArgumentModification::setPyiType(const QString &value) { if (d->pyiType != value) d->pyiType = value; } QString ArgumentModification::replacedDefaultExpression() const { return d->replacedDefaultExpression; } void ArgumentModification::setReplacedDefaultExpression(const QString &value) { if (d->replacedDefaultExpression != value) d->replacedDefaultExpression = value; } TypeSystem::Ownership ArgumentModification::targetOwnerShip() const { return d->m_targetOwnerShip; } void ArgumentModification::setTargetOwnerShip(TypeSystem::Ownership o) { if (o != d->m_targetOwnerShip) d->m_targetOwnerShip = o; } TypeSystem::Ownership ArgumentModification::nativeOwnership() const { return d->m_nativeOwnerShip; } void ArgumentModification::setNativeOwnership(TypeSystem::Ownership o) { if (o != d->m_nativeOwnerShip) d->m_nativeOwnerShip = o; } const CodeSnipList &ArgumentModification::conversionRules() const { return d->conversion_rules; } CodeSnipList &ArgumentModification::conversionRules() { return d->conversion_rules; } ArgumentOwner ArgumentModification::owner() const { return d->owner; } void ArgumentModification::setOwner(const ArgumentOwner &value) { d->owner = value; } QString ArgumentModification::renamedToName() const { return d->renamed_to; } void ArgumentModification::setRenamedToName(const QString &value) { if (d->renamed_to != value) d->renamed_to = value; } int ArgumentModification::index() const { return d->index; } void ArgumentModification::setIndex(int value) { if (d->index != value) d->index = value; } bool ArgumentModification::removedDefaultExpression() const { return d->removedDefaultExpression; } void ArgumentModification::setRemovedDefaultExpression(const uint &value) { if (d->removedDefaultExpression != value) d->removedDefaultExpression = value; } bool ArgumentModification::isRemoved() const { return d->removed; } void ArgumentModification::setRemoved(bool value) { if (d->removed != value) d->removed = value; } bool ArgumentModification::noNullPointers() const { return d->noNullPointers; } void ArgumentModification::setNoNullPointers(bool value) { if (d->noNullPointers != value) d->noNullPointers = value; } bool ArgumentModification::resetAfterUse() const { return d->resetAfterUse; } void ArgumentModification::setResetAfterUse(bool value) { if (d->resetAfterUse != value) d->resetAfterUse = value; } bool ArgumentModification::isArray() const { return d->array; } void ArgumentModification::setArray(bool value) { if (d->array != value) d->array = value; } const QList &ArgumentModification::referenceCounts() const { return d->referenceCounts; } void ArgumentModification::addReferenceCount(const ReferenceCount &value) { d->referenceCounts.append(value); } bool ArgumentModification::equals(const ArgumentModification &rhs) const noexcept { return d.constData() == rhs.d.constData() || d->equals(*rhs.d); } size_t ArgumentModification::hash(size_t seed) const noexcept { return d->hash(seed); } class FunctionModificationData : public QSharedData { public: bool equals(const FunctionModificationData &rhs) const noexcept; size_t hash(size_t seed) const noexcept; QString renamedToName; FunctionModification::Modifiers modifiers; CodeSnipList m_snips; QList m_argument_mods; QString m_signature; QString m_originalSignature; QRegularExpression m_signaturePattern; int m_overloadNumber = TypeSystem::OverloadNumberUnset; bool removed = false; bool inherited = false; TypeSystem::AllowThread m_allowThread = TypeSystem::AllowThread::Unspecified; TypeSystem::ExceptionHandling m_exceptionHandling = TypeSystem::ExceptionHandling::Unspecified; TypeSystem::SnakeCase snakeCase = TypeSystem::SnakeCase::Unspecified; }; bool FunctionModificationData::equals(const FunctionModificationData &rhs) const noexcept { return renamedToName == rhs.renamedToName && modifiers == rhs.modifiers && m_snips == rhs.m_snips && m_argument_mods == rhs.m_argument_mods && m_signature == rhs.m_signature && m_originalSignature == rhs.m_originalSignature && m_signaturePattern == rhs.m_signaturePattern && m_overloadNumber == rhs.m_overloadNumber && removed == rhs.removed && inherited == rhs.inherited && m_allowThread == rhs.m_allowThread && m_exceptionHandling == rhs.m_exceptionHandling && snakeCase == rhs.snakeCase; } size_t FunctionModificationData::hash(size_t seed) const noexcept { return qHashMulti(seed, renamedToName, modifiers, m_snips, m_argument_mods, m_signature, m_originalSignature, m_signaturePattern, m_overloadNumber, removed, inherited, m_allowThread, m_exceptionHandling, snakeCase); } FunctionModification::FunctionModification() : d(new FunctionModificationData) { } FunctionModification::FunctionModification(const FunctionModification &) = default; FunctionModification &FunctionModification::operator=(const FunctionModification &) = default; FunctionModification::FunctionModification(FunctionModification &&) noexcept = default; FunctionModification &FunctionModification::operator=(FunctionModification &&) noexcept = default; FunctionModification::~FunctionModification() = default; bool FunctionModification::equals(const FunctionModification &rhs) const noexcept { return d.constData() == rhs.d.constData() || d->equals(*rhs.d); } size_t FunctionModification::hash(size_t seed) const noexcept { return d->hash(seed); } void FunctionModification::formatDebug(QDebug &debug) const { if (d->m_signature.isEmpty()) debug << "pattern=\"" << d->m_signaturePattern.pattern(); else debug << "signature=\"" << d->m_signature; debug << "\", modifiers=" << d->modifiers; if (d->removed) debug << ", removed"; if (!d->renamedToName.isEmpty()) debug << ", renamedToName=\"" << d->renamedToName << '"'; if (d->m_allowThread != TypeSystem::AllowThread::Unspecified) debug << ", allowThread=" << int(d->m_allowThread); if (d->m_exceptionHandling != TypeSystem::ExceptionHandling::Unspecified) debug << ", exceptionHandling=" << int(d->m_exceptionHandling); if (!d->m_snips.isEmpty()) debug << ", snips=(" << d->m_snips << ')'; if (!d->m_argument_mods.isEmpty()) debug << ", argument_mods=(" << d->m_argument_mods << ')'; } QString FunctionModification::renamedToName() const { return d->renamedToName; } void FunctionModification::setRenamedToName(const QString &value) { if (d->renamedToName != value) d->renamedToName = value; } FunctionModification::Modifiers FunctionModification::modifiers() const { return d->modifiers; } void FunctionModification::setModifiers(Modifiers m) { if (d->modifiers != m) d->modifiers = m; } void FunctionModification::setModifierFlag(FunctionModification::ModifierFlag f) { auto newMods = d->modifiers | f; if (d->modifiers != newMods) d->modifiers = newMods; } void FunctionModification::clearModifierFlag(ModifierFlag f) { auto newMods = d->modifiers & ~f; if (d->modifiers != newMods) d->modifiers = newMods; } bool FunctionModification::isRemoved() const { return d->removed; } void FunctionModification::setRemoved(bool r) { if (d->removed != r) d->removed = r; } bool FunctionModification::isInherited() const { return d->inherited; } void FunctionModification::setInherited(bool i) { if (d->inherited != i) d->inherited = i; } const QList &FunctionModification::argument_mods() const { return d->m_argument_mods; } QList &FunctionModification::argument_mods() { return d->m_argument_mods; } void FunctionModification::setArgument_mods(const QList &argument_mods) { d->m_argument_mods = argument_mods; } TypeSystem::SnakeCase FunctionModification::snakeCase() const { return d->snakeCase; } void FunctionModification::setSnakeCase(TypeSystem::SnakeCase s) { if (d->snakeCase != s) d->snakeCase = s; } const CodeSnipList &FunctionModification::snips() const { return d->m_snips; } CodeSnipList &FunctionModification::snips() { return d->m_snips; } void FunctionModification::appendSnip(const CodeSnip &snip) { d->m_snips.append(snip); } void FunctionModification::setSnips(const CodeSnipList &snips) { d->m_snips = snips; } // ---------------------- FunctionModification FunctionModification::AllowThread FunctionModification::allowThread() const { return d->m_allowThread; } void FunctionModification::setAllowThread(FunctionModification::AllowThread allow) { if (d->m_allowThread != allow) d->m_allowThread = allow; } bool FunctionModification::matches(const QStringList &functionSignatures) const { if (!d->m_signature.isEmpty()) return functionSignatures.contains(d->m_signature); const auto &pattern = d->m_signaturePattern; return std::any_of(functionSignatures.cbegin(), functionSignatures.end(), [&pattern] (const QString &s) { return pattern.match(s).hasMatch(); }); } bool FunctionModification::setSignature(const QString &s, QString *errorMessage) { if (s.startsWith(u'^')) { d->m_signaturePattern.setPattern(s); if (!d->m_signaturePattern.isValid()) { if (errorMessage) { *errorMessage = u"Invalid signature pattern: \""_s + s + u"\": "_s + d->m_signaturePattern.errorString(); } return false; } } else { d->m_signature = s; } return true; } QString FunctionModification::signature() const { return d->m_signature.isEmpty() ? d->m_signaturePattern.pattern() : d->m_signature; } void FunctionModification::setOriginalSignature(const QString &s) { if (d->m_originalSignature != s) d->m_originalSignature = s; } QString FunctionModification::originalSignature() const { return d->m_originalSignature; } TypeSystem::ExceptionHandling FunctionModification::exceptionHandling() const { return d->m_exceptionHandling; } void FunctionModification::setExceptionHandling(TypeSystem::ExceptionHandling e) { if (d->m_exceptionHandling != e) d->m_exceptionHandling = e; } int FunctionModification::overloadNumber() const { return d->m_overloadNumber; } void FunctionModification::setOverloadNumber(int overloadNumber) { d->m_overloadNumber = overloadNumber; } 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.isRemoved()) d << ", removed"; if (a.noNullPointers()) d << ", noNullPointers"; if (a.isArray()) d << ", array"; if (!a.referenceCounts().isEmpty()) d << ", referenceCounts=" << a.referenceCounts(); if (!a.modifiedType().isEmpty()) d << ", modified_type=\"" << a.modifiedType() << '"'; if (!a.replacedDefaultExpression().isEmpty()) d << ", replacedDefaultExpression=\"" << a.replacedDefaultExpression() << '"'; if (a.targetOwnerShip() != TypeSystem::UnspecifiedOwnership) d << ", target ownership=" << a.targetOwnerShip(); if (a.nativeOwnership() != TypeSystem::UnspecifiedOwnership) d << ", native ownership=" << a.nativeOwnership(); if (!a.renamedToName().isEmpty()) d << ", renamed_to=\"" << a.renamedToName() << '"'; const auto &rules = a.conversionRules(); if (!rules.isEmpty()) d << ", conversionRules[" << rules.size() << "]=" << rules; 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; } #endif // !QT_NO_DEBUG_STREAM