aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/ApiExtractor/propertyspec.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/ApiExtractor/propertyspec.cpp')
-rw-r--r--sources/shiboken6/ApiExtractor/propertyspec.cpp347
1 files changed, 347 insertions, 0 deletions
diff --git a/sources/shiboken6/ApiExtractor/propertyspec.cpp b/sources/shiboken6/ApiExtractor/propertyspec.cpp
new file mode 100644
index 000000000..32b756fad
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/propertyspec.cpp
@@ -0,0 +1,347 @@
+// 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 "propertyspec.h"
+#include "abstractmetalang.h"
+#include "abstractmetabuilder_p.h"
+#include "abstractmetatype.h"
+#include "documentation.h"
+#include "messages.h"
+#include "complextypeentry.h"
+#include "typeinfo.h"
+
+#include "qtcompat.h"
+
+#include <QtCore/QHash>
+
+#ifndef QT_NO_DEBUG_STREAM
+# include <QtCore/QDebug>
+#endif
+
+#include <algorithm>
+
+using namespace Qt::StringLiterals;
+
+class QPropertySpecData : public QSharedData
+{
+public:
+ QPropertySpecData(const TypeSystemProperty &ts,
+ const AbstractMetaType &type) :
+ m_name(ts.name),
+ m_read(ts.read),
+ m_write(ts.write),
+ m_designable(ts.designable),
+ m_reset(ts.reset),
+ m_notify(ts.notify),
+ m_type(type),
+ m_generateGetSetDef(ts.generateGetSetDef)
+ {
+ }
+
+ QString m_name;
+ QString m_read;
+ QString m_write;
+ QString m_designable;
+ QString m_reset;
+ QString m_notify;
+ Documentation m_documentation;
+ AbstractMetaType m_type;
+ int m_index = -1;
+ // Indicates whether actual code is generated instead of relying on libpyside.
+ bool m_generateGetSetDef = false;
+};
+
+QPropertySpec::QPropertySpec(const TypeSystemProperty &ts,
+ const AbstractMetaType &type) :
+ d(new QPropertySpecData(ts, type))
+{
+}
+
+QPropertySpec::QPropertySpec(const QPropertySpec &) = default;
+QPropertySpec &QPropertySpec::operator=(const QPropertySpec &) = default;
+QPropertySpec::QPropertySpec(QPropertySpec &&) noexcept = default;
+QPropertySpec &QPropertySpec::operator=(QPropertySpec &&) noexcept = default;
+QPropertySpec::~QPropertySpec() = default;
+
+const AbstractMetaType &QPropertySpec::type() const
+{
+ return d->m_type;
+}
+
+void QPropertySpec::setType(const AbstractMetaType &t)
+{
+ if (d->m_type != t)
+ d->m_type = t;
+}
+
+TypeEntryCPtr QPropertySpec::typeEntry() const
+{
+ return d->m_type.typeEntry();
+}
+
+QString QPropertySpec::name() const
+{
+ return d->m_name;
+}
+
+void QPropertySpec::setName(const QString &name)
+{
+ if (d->m_name != name)
+ d->m_name = name;
+}
+
+Documentation QPropertySpec::documentation() const
+{
+ return d->m_documentation;
+}
+
+void QPropertySpec::setDocumentation(const Documentation &doc)
+{
+ if (d->m_documentation != doc)
+ d->m_documentation = doc;
+}
+
+QString QPropertySpec::read() const
+{
+ return d->m_read;
+}
+
+void QPropertySpec::setRead(const QString &read)
+{
+ if (d->m_read != read)
+ d->m_read = read;
+}
+
+QString QPropertySpec::write() const
+{
+ return d->m_write;
+}
+
+void QPropertySpec::setWrite(const QString &write)
+{
+ if (d->m_write != write)
+ d->m_write = write;
+}
+
+bool QPropertySpec::hasWrite() const
+{
+ return !d->m_write.isEmpty();
+}
+
+QString QPropertySpec::designable() const
+{
+ return d->m_designable;
+}
+
+void QPropertySpec::setDesignable(const QString &designable)
+{
+ if (d->m_designable != designable)
+ d->m_designable = designable;
+}
+
+QString QPropertySpec::reset() const
+{
+ return d->m_reset;
+}
+
+void QPropertySpec::setReset(const QString &reset)
+{
+ if (d->m_reset != reset)
+ d->m_reset = reset;
+}
+
+QString QPropertySpec::notify() const
+{
+ return d->m_notify;
+}
+
+void QPropertySpec::setNotify(const QString &notify)
+{
+ if (d->m_notify != notify)
+ d->m_notify = notify;
+}
+
+int QPropertySpec::index() const
+{
+ return d->m_index;
+}
+
+void QPropertySpec::setIndex(int index)
+{
+ if (d->m_index != index)
+ d->m_index = index;
+}
+
+bool QPropertySpec::generateGetSetDef() const
+{
+ return d->m_generateGetSetDef;
+}
+
+void QPropertySpec::setGenerateGetSetDef(bool generateGetSetDef)
+{
+ if (d->m_generateGetSetDef != generateGetSetDef)
+ d->m_generateGetSetDef = generateGetSetDef;
+}
+
+// Parse a Q_PROPERTY macro
+// Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)
+// into a TypeSystemProperty.
+TypeSystemProperty QPropertySpec::typeSystemPropertyFromQ_Property(const QString &declarationIn,
+ QString *errorMessage)
+{
+ enum class PropertyToken { None, Read, Write, Designable, Reset, Notify, Member };
+
+ static const QHash<QString, PropertyToken> tokenLookup = {
+ {"READ"_L1, PropertyToken::Read},
+ {"WRITE"_L1, PropertyToken::Write},
+ {"DESIGNABLE"_L1, PropertyToken::Designable},
+ {"RESET"_L1, PropertyToken::Reset},
+ {"NOTIFY"_L1, PropertyToken::Notify},
+ {"MEMBER"_L1, PropertyToken::Member}
+ };
+
+ errorMessage->clear();
+
+ TypeSystemProperty result;
+
+ // Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)
+
+ const QString declaration = declarationIn.simplified();
+ auto propertyTokens = declaration.split(u' ', Qt::SkipEmptyParts);
+
+ // To properly parse complicated type declarations like
+ // "Q_PROPERTY(const QList<QString > *objectName READ objectName ..."
+ // we first search the first "READ" token, parse the subsequent tokens and
+ // extract type and name from the tokens before "READ".
+ const auto it = std::find_if(propertyTokens.cbegin(), propertyTokens.cend(),
+ [](const QString &t) { return tokenLookup.contains(t); });
+ if (it == propertyTokens.cend()) {
+ *errorMessage = u"Invalid property specification, READ missing"_s;
+ return result;
+ }
+
+ const auto firstToken = qsizetype(it - propertyTokens.cbegin());
+ if (firstToken < 2) {
+ *errorMessage = u"Insufficient number of tokens in property specification"_s;
+ return result;
+ }
+
+ for (qsizetype pos = firstToken; pos + 1 < propertyTokens.size(); pos += 2) {
+ switch (tokenLookup.value(propertyTokens.at(pos))) {
+ case PropertyToken::Read:
+ result.read = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Write:
+ result.write = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Reset:
+ result.reset = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Designable:
+ result.designable = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Notify:
+ result.notify = propertyTokens.at(pos + 1);
+ break;
+ case PropertyToken::Member:
+ // Ignore MEMBER tokens introduced by QTBUG-16852 as Python
+ // properties are anyways generated for fields.
+ return {};
+
+ case PropertyToken::None:
+ break;
+ }
+ }
+
+ const auto namePos = firstToken - 1;
+ result.name = propertyTokens.at(namePos);
+
+ result.type = propertyTokens.constFirst();
+ for (qsizetype pos = 1; pos < namePos; ++pos)
+ result.type += u' ' + propertyTokens.at(pos);
+
+ // Fix errors like "Q_PROPERTY(QXYSeries *series .." to be of type "QXYSeries*"
+ while (!result.name.isEmpty() && !result.name.at(0).isLetter()) {
+ result.type += result.name.at(0);
+ result.name.remove(0, 1);
+ }
+ if (!result.isValid())
+ *errorMessage = u"Incomplete property specification"_s;
+ return result;
+}
+
+// Create a QPropertySpec from a TypeSystemProperty, determining
+// the AbstractMetaType from the type string.
+std::optional<QPropertySpec>
+ QPropertySpec::fromTypeSystemProperty(AbstractMetaBuilderPrivate *b,
+ const AbstractMetaClassPtr &metaClass,
+ const TypeSystemProperty &ts,
+ const QStringList &scopes,
+ QString *errorMessage)
+ {
+ Q_ASSERT(ts.isValid());
+ QString typeError;
+ TypeInfo info = TypeParser::parse(ts.type, &typeError);
+ if (info.qualifiedName().isEmpty()) {
+ *errorMessage = msgPropertyTypeParsingFailed(ts.name, ts.type, typeError);
+ return {};
+ }
+
+ auto type = b->translateType(info, metaClass, {}, &typeError);
+ if (!type.has_value()) {
+ const QStringList qualifiedName = info.qualifiedName();
+ for (auto j = scopes.size(); j >= 0 && !type; --j) {
+ info.setQualifiedName(scopes.mid(0, j) + qualifiedName);
+ type = b->translateType(info, metaClass, {}, &typeError);
+ }
+ }
+
+ if (!type.has_value()) {
+ *errorMessage = msgPropertyTypeParsingFailed(ts.name, ts.type, typeError);
+ return {};
+ }
+ return QPropertySpec(ts, type.value());
+ }
+
+// Convenience to create a QPropertySpec from a Q_PROPERTY macro
+// via TypeSystemProperty.
+std::optional<QPropertySpec>
+ QPropertySpec::parseQ_Property(AbstractMetaBuilderPrivate *b,
+ const AbstractMetaClassPtr &metaClass,
+ const QString &declarationIn,
+ const QStringList &scopes,
+ QString *errorMessage)
+{
+ const TypeSystemProperty ts =
+ typeSystemPropertyFromQ_Property(declarationIn, errorMessage);
+ if (!ts.isValid())
+ return {};
+ return fromTypeSystemProperty(b, metaClass, ts, scopes, errorMessage);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void QPropertySpec::formatDebug(QDebug &debug) const
+{
+ debug << '#' << d->m_index << " \"" << d->m_name << "\" (" << d->m_type.cppSignature();
+ debug << "), read=" << d->m_read;
+ if (!d->m_write.isEmpty())
+ debug << ", write=" << d->m_write;
+ if (!d->m_reset.isEmpty())
+ debug << ", reset=" << d->m_reset;
+ if (!d->m_designable.isEmpty())
+ debug << ", designable=" << d->m_designable;
+ if (!d->m_documentation.isEmpty())
+ debug << ", doc=\"" << d->m_documentation << '"';
+}
+
+QDebug operator<<(QDebug d, const QPropertySpec &p)
+{
+ QDebugStateSaver s(d);
+ d.noquote();
+ d.nospace();
+ d << "QPropertySpec(";
+ p.formatDebug(d);
+ d << ')';
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM