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.cpp215
1 files changed, 215 insertions, 0 deletions
diff --git a/sources/shiboken6/ApiExtractor/propertyspec.cpp b/sources/shiboken6/ApiExtractor/propertyspec.cpp
new file mode 100644
index 000000000..d15647fda
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/propertyspec.cpp
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** 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 "propertyspec.h"
+#include "abstractmetalang.h"
+#include "abstractmetabuilder_p.h"
+#include "codemodel.h"
+#include "messages.h"
+#include "typesystem.h"
+
+#include <QtCore/QHash>
+
+#ifndef QT_NO_DEBUG_STREAM
+# include <QtCore/QDebug>
+#endif
+
+#include <algorithm>
+
+QPropertySpec::QPropertySpec(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_type(type),
+ m_generateGetSetDef(ts.generateGetSetDef)
+{
+}
+
+QPropertySpec::~QPropertySpec() = default;
+
+bool QPropertySpec::isValid() const
+{
+ return m_type.isValid() && !m_name.isEmpty() && !m_read.isEmpty();
+}
+
+const TypeEntry *QPropertySpec::typeEntry() const
+{
+ return m_type.typeEntry();
+}
+
+// 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 };
+
+ static const QHash<QString, PropertyToken> tokenLookup = {
+ {QStringLiteral("READ"), PropertyToken::Read},
+ {QStringLiteral("WRITE"), PropertyToken::Write},
+ {QStringLiteral("DESIGNABLE"), PropertyToken::Designable},
+ {QStringLiteral("RESET"), PropertyToken::Reset}
+ };
+
+ errorMessage->clear();
+
+ TypeSystemProperty result;
+
+ // Q_PROPERTY(QString objectName READ objectName WRITE setObjectName NOTIFY objectNameChanged)
+
+ const QString declaration = declarationIn.simplified();
+ auto propertyTokens = declaration.split(QLatin1Char(' '), 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 = QLatin1String("Invalid property specification, READ missing");
+ return result;
+ }
+
+ const int firstToken = int(it - propertyTokens.cbegin());
+ if (firstToken < 2) {
+ *errorMessage = QLatin1String("Insufficient number of tokens in property specification");
+ return result;
+ }
+
+ for (int 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::None:
+ break;
+ }
+ }
+
+ const int namePos = firstToken - 1;
+ result.name = propertyTokens.at(namePos);
+
+ result.type = propertyTokens.constFirst();
+ for (int pos = 1; pos < namePos; ++pos)
+ result.type += QLatin1Char(' ') + 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 = QLatin1String("Incomplete property specification");
+ return result;
+}
+
+// Create a QPropertySpec from a TypeSystemProperty, determining
+// the AbstractMetaType from the type string.
+QPropertySpec *QPropertySpec::fromTypeSystemProperty(AbstractMetaBuilderPrivate *b,
+ AbstractMetaClass *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 nullptr;
+ }
+
+ AbstractMetaType type = b->translateType(info, metaClass, {}, &typeError);
+ if (!type) {
+ const QStringList qualifiedName = info.qualifiedName();
+ for (int j = scopes.size(); j >= 0 && !type; --j) {
+ info.setQualifiedName(scopes.mid(0, j) + qualifiedName);
+ type = b->translateType(info, metaClass, {}, &typeError);
+ }
+ }
+
+ if (!type) {
+ *errorMessage = msgPropertyTypeParsingFailed(ts.name, ts.type, typeError);
+ return nullptr;
+ }
+ return new QPropertySpec(ts, type);
+ }
+
+// Convenience to create a QPropertySpec from a Q_PROPERTY macro
+// via TypeSystemProperty.
+QPropertySpec *QPropertySpec::parseQ_Property(AbstractMetaBuilderPrivate *b,
+ AbstractMetaClass *metaClass,
+ const QString &declarationIn,
+ const QStringList &scopes,
+ QString *errorMessage)
+{
+ const TypeSystemProperty ts =
+ typeSystemPropertyFromQ_Property(declarationIn, errorMessage);
+ return ts.isValid()
+ ? fromTypeSystemProperty(b, metaClass, ts, scopes, errorMessage)
+ : nullptr;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+void QPropertySpec::formatDebug(QDebug &d) const
+{
+ d << '#' << m_index << " \"" << m_name << "\" (" << m_type.cppSignature();
+ d << "), read=" << m_read;
+ if (!m_write.isEmpty())
+ d << ", write=" << m_write;
+ if (!m_reset.isEmpty())
+ d << ", reset=" << m_reset;
+ if (!m_designable.isEmpty())
+ d << ", designable=" << m_designable;
+}
+
+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