diff options
-rw-r--r-- | src/qmlcompiler/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/qmlcompiler/qdeferredpointer_p.h | 181 | ||||
-rw-r--r-- | src/qmlcompiler/qmlcompiler.pro | 1 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimporter.cpp | 26 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimporter_p.h | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 2 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope.cpp | 25 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsscope_p.h | 41 | ||||
-rw-r--r-- | tools/qmllint/checkidentifiers.cpp | 6 | ||||
-rw-r--r-- | tools/qmllint/findwarnings.cpp | 6 |
10 files changed, 259 insertions, 32 deletions
diff --git a/src/qmlcompiler/CMakeLists.txt b/src/qmlcompiler/CMakeLists.txt index 0eab79259f..d0e9be9418 100644 --- a/src/qmlcompiler/CMakeLists.txt +++ b/src/qmlcompiler/CMakeLists.txt @@ -8,6 +8,7 @@ qt_internal_add_module(QmlCompiler STATIC INTERNAL_MODULE SOURCES + qdeferredpointer_p.h qqmljsimporter.cpp qqmljsimporter_p.h qqmljsimportvisitor.cpp qqmljsimportvisitor_p.h qqmljsmetatypes_p.h diff --git a/src/qmlcompiler/qdeferredpointer_p.h b/src/qmlcompiler/qdeferredpointer_p.h new file mode 100644 index 0000000000..07875013fa --- /dev/null +++ b/src/qmlcompiler/qdeferredpointer_p.h @@ -0,0 +1,181 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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$ +** +****************************************************************************/ + +#ifndef QDEFERREDPOINTER_P_H +#define QDEFERREDPOINTER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. + +#include <QtCore/qglobal.h> +#include <QtCore/qsharedpointer.h> + +QT_BEGIN_NAMESPACE + +template<typename T> +class QDeferredFactory +{ +public: + T create() const; + bool isValid() const; + void clear(); +}; + +template<typename T> +class QDeferredWeakPointer; + +template<typename T> +class QDeferredSharedPointer +{ +public: + using Factory = QDeferredFactory<std::remove_const_t<T>>; + + QDeferredSharedPointer() = default; + + QDeferredSharedPointer(QSharedPointer<T> data) + : m_data(data) + {} + + QDeferredSharedPointer(QWeakPointer<T> data) + : m_data(data) + {} + + QDeferredSharedPointer(QSharedPointer<T> data, QSharedPointer<Factory> factory) + : m_data(data), m_factory(factory) + {} + + operator QSharedPointer<T>() const + { + if (m_factory && m_factory->isValid()) { + const_cast<std::remove_const_t<T> &>(*m_data) = m_factory->create(); + m_factory->clear(); + } + return m_data; + } + + operator QDeferredSharedPointer<const T>() const { return { m_data, m_factory }; } + + T &operator*() const { return QSharedPointer<T>(*this).operator*(); } + T *operator->() const { return QSharedPointer<T>(*this).operator->(); } + + bool isNull() const { return m_data.isNull(); } + explicit operator bool() const noexcept { return !isNull(); } + bool operator !() const noexcept { return isNull(); } + + T *data() const { return QSharedPointer<T>(*this).data(); } + + friend qsizetype qHash(const QDeferredSharedPointer &ptr, qsizetype seed = 0) + { + return qHashMulti(seed, ptr.m_factory, ptr.m_data); + } + + friend bool operator==(const QDeferredSharedPointer &a, const QDeferredSharedPointer &b) + { + return a.m_factory == b.m_factory && a.m_data == b.m_data; + } + +private: + friend class QDeferredWeakPointer<T>; + + QSharedPointer<T> m_data; + QSharedPointer<Factory> m_factory; +}; + +template<typename T> +class QDeferredWeakPointer +{ +public: + using Factory = QDeferredFactory<std::remove_const_t<T>>; + + QDeferredWeakPointer() = default; + + QDeferredWeakPointer(const QDeferredSharedPointer<T> &strong) + : m_data(strong.m_data), m_factory(strong.m_factory) + { + } + + QDeferredWeakPointer(QWeakPointer<T> data, QWeakPointer<Factory> factory) + : m_data(data), m_factory(factory) + {} + + operator QWeakPointer<T>() const + { + if (m_factory) { + auto factory = m_factory.toStrongRef(); + if (factory->isValid()) { + const_cast<std::remove_const_t<T> &>(*(m_data.toStrongRef())) = factory->create(); + factory->clear(); + } + } + return m_data; + } + + operator QDeferredSharedPointer<T>() const + { + return QDeferredSharedPointer<T>(m_data.toStrongRef(), m_factory.toStrongRef()); + } + + operator QDeferredWeakPointer<const T>() const { return {m_data, m_factory}; } + + QSharedPointer<T> toStrongRef() const + { + return QWeakPointer<T>(*this).toStrongRef(); + } + + bool isNull() const { return m_data.isNull(); } + explicit operator bool() const noexcept { return !isNull(); } + bool operator !() const noexcept { return isNull(); } + + T *data() const { return QWeakPointer<T>(*this).data(); } + + friend qsizetype qHash(const QDeferredWeakPointer &ptr, qsizetype seed = 0) + { + return qHashMulti(seed, ptr.m_factory, ptr.m_data); + } + + friend bool operator==(const QDeferredWeakPointer &a, const QDeferredWeakPointer &b) + { + return a.m_factory == b.m_factory && a.m_data == b.m_data; + } + +private: + QWeakPointer<T> m_data; + QWeakPointer<Factory> m_factory; +}; + + +QT_END_NAMESPACE + +#endif // QDEFERREDPOINTER_P_H diff --git a/src/qmlcompiler/qmlcompiler.pro b/src/qmlcompiler/qmlcompiler.pro index 111d27932a..37a1b44b9c 100644 --- a/src/qmlcompiler/qmlcompiler.pro +++ b/src/qmlcompiler/qmlcompiler.pro @@ -13,6 +13,7 @@ SOURCES = \ qqmljsstreamwriter.cpp HEADERS = \ + qdeferredpointer_p.h \ qqmljsresourcefilemapper_p.h \ qqmljsimportvisitor_p.h \ qqmljsimporter_p.h \ diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp index 717b559c44..0f334eabd3 100644 --- a/src/qmlcompiler/qqmljsimporter.cpp +++ b/src/qmlcompiler/qqmljsimporter.cpp @@ -303,21 +303,11 @@ QQmlJSScope::Ptr QQmlJSImporter::localFile2ScopeTree(const QString &filePath) if (seen != m_importedFiles.end()) return *seen; - QQmlJSTypeReader typeReader(filePath); - QQmlJSScope::Ptr result = typeReader(); - m_importedFiles.insert(filePath, result); - - m_warnings.append(typeReader.errors()); - - AvailableTypes types; - types.qmlNames.insert(importDirectory(QFileInfo(filePath).canonicalPath())); - - const auto imports = typeReader.imports(); - for (const auto &import : imports) - importHelper(import.module, &types, import.prefix, import.version); - - result->resolveTypes(types.qmlNames); - return result; + return *m_importedFiles.insert(filePath, { + QQmlJSScope::create(), + QSharedPointer<QDeferredFactory<QQmlJSScope>>( + new QDeferredFactory<QQmlJSScope>(this, filePath)) + }); } QQmlJSScope::Ptr QQmlJSImporter::importFile(const QString &file) @@ -339,9 +329,9 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importDirectory( it.next(); if (!it.fileName().front().isUpper()) continue; // Non-uppercase names cannot be imported anyway. - QQmlJSScope::Ptr scope(localFile2ScopeTree(it.filePath())); - if (!scope->internalName().isEmpty()) - qmlNames.insert(prefixedName(prefix, scope->internalName()), scope); + + qmlNames.insert(prefixedName(prefix, QFileInfo(it.filePath()).baseName()), + localFile2ScopeTree(it.filePath())); } return qmlNames; diff --git a/src/qmlcompiler/qqmljsimporter_p.h b/src/qmlcompiler/qqmljsimporter_p.h index 1acd2a5ed1..3356997fd3 100644 --- a/src/qmlcompiler/qqmljsimporter_p.h +++ b/src/qmlcompiler/qqmljsimporter_p.h @@ -69,6 +69,8 @@ public: } private: + friend class QDeferredFactory<QQmlJSScope>; + struct AvailableTypes { // C++ names used in qmltypes files for non-composite types diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index 0b79339b62..0cb5632d40 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -43,7 +43,7 @@ QQmlJSScope::Ptr QQmlJSImportVisitor::result(const QString &scopeName) const if (property.isAlias()) { const auto it = m_objects.find(property.typeName()); if (it != m_objects.end()) - property.setType(*it); + property.setType(QQmlJSScope::ConstPtr(*it)); result->addProperty(property); } else { result->addProperty(property); diff --git a/src/qmlcompiler/qqmljsscope.cpp b/src/qmlcompiler/qqmljsscope.cpp index b2b9443fc6..e515431758 100644 --- a/src/qmlcompiler/qqmljsscope.cpp +++ b/src/qmlcompiler/qqmljsscope.cpp @@ -27,9 +27,12 @@ ****************************************************************************/ #include "qqmljsscope_p.h" +#include "qqmljstypereader_p.h" +#include "qqmljsimporter_p.h" #include <QtCore/qqueue.h> #include <QtCore/qsharedpointer.h> +#include <QtCore/qfileinfo.h> #include <algorithm> @@ -40,7 +43,7 @@ QQmlJSScope::QQmlJSScope(ScopeType type, const QQmlJSScope::Ptr &parentScope) QQmlJSScope::Ptr QQmlJSScope::create(ScopeType type, const QQmlJSScope::Ptr &parentScope) { - QQmlJSScope::Ptr childScope(new QQmlJSScope{type, parentScope}); + QSharedPointer<QQmlJSScope> childScope(new QQmlJSScope{type, parentScope}); if (parentScope) { Q_ASSERT(type != QQmlJSScope::QMLScope || !parentScope->m_parentScope @@ -142,7 +145,7 @@ void QQmlJSScope::resolveTypes(const QHash<QString, QQmlJSScope::ConstPtr> &cont for (auto it = m_methods.begin(), end = m_methods.end(); it != end; ++it) { it->setReturnType(findType(it->returnTypeName())); const auto paramNames = it->parameterTypeNames(); - QList<QQmlJSScope::ConstPtr> paramTypes; + QList<QSharedPointer<const QQmlJSScope>> paramTypes; for (const QString ¶mName: paramNames) paramTypes.append(findType(paramName)); @@ -183,4 +186,22 @@ bool QQmlJSScope::Export::isValid() const return m_version.isValid() || !m_package.isEmpty() || !m_type.isEmpty(); } +QQmlJSScope QDeferredFactory<QQmlJSScope>::create() const +{ + QQmlJSTypeReader typeReader(m_filePath); + QQmlJSScope::Ptr result = typeReader(); + + m_importer->m_warnings.append(typeReader.errors()); + + QQmlJSImporter::AvailableTypes types; + types.qmlNames.insert(m_importer->importDirectory(QFileInfo(m_filePath).canonicalPath())); + + const auto imports = typeReader.imports(); + for (const auto &import : imports) + m_importer->importHelper(import.module, &types, import.prefix, import.version); + + result->resolveTypes(types.qmlNames); + return std::move(*result); +} + QT_END_NAMESPACE diff --git a/src/qmlcompiler/qqmljsscope_p.h b/src/qmlcompiler/qqmljsscope_p.h index 4cf1d4cd6c..df7aad840d 100644 --- a/src/qmlcompiler/qqmljsscope_p.h +++ b/src/qmlcompiler/qqmljsscope_p.h @@ -40,6 +40,7 @@ // We mean it. #include "qqmljsmetatypes_p.h" +#include "qdeferredpointer_p.h" #include <QtQml/private/qqmljssourcelocation_p.h> @@ -52,15 +53,45 @@ QT_BEGIN_NAMESPACE +class QQmlJSImporter; +class QQmlJSScope; + +template<> +class QDeferredFactory<QQmlJSScope> +{ +public: + QDeferredFactory(QQmlJSImporter *importer, const QString &filePath) : + m_filePath(filePath), m_importer(importer) + {} + + QQmlJSScope create() const; + + bool isValid() const + { + return !m_filePath.isEmpty() && m_importer != nullptr; + } + + void clear() { + m_filePath.clear(); + m_importer = nullptr; + } + +private: + QString m_filePath; + QQmlJSImporter *m_importer = nullptr; +}; class QQmlJSScope { - Q_DISABLE_COPY_MOVE(QQmlJSScope) + Q_DISABLE_COPY(QQmlJSScope) public: - using Ptr = QSharedPointer<QQmlJSScope>; - using WeakPtr = QWeakPointer<QQmlJSScope>; - using ConstPtr = QSharedPointer<const QQmlJSScope>; - using WeakConstPtr = QWeakPointer<const QQmlJSScope>; + QQmlJSScope(QQmlJSScope &&) = default; + QQmlJSScope &operator=(QQmlJSScope &&) = default; + + using Ptr = QDeferredSharedPointer<QQmlJSScope>; + using WeakPtr = QDeferredWeakPointer<QQmlJSScope>; + using ConstPtr = QDeferredSharedPointer<const QQmlJSScope>; + using WeakConstPtr = QDeferredWeakPointer<const QQmlJSScope>; enum ScopeType { diff --git a/tools/qmllint/checkidentifiers.cpp b/tools/qmllint/checkidentifiers.cpp index 6fa26b86ba..b7d331521c 100644 --- a/tools/qmllint/checkidentifiers.cpp +++ b/tools/qmllint/checkidentifiers.cpp @@ -82,7 +82,7 @@ void CheckIdentifiers::printContext( static bool walkViaParentAndAttachedScopes(QQmlJSScope::ConstPtr rootType, std::function<bool(QQmlJSScope::ConstPtr)> visit) { - if (rootType == nullptr) + if (rootType.isNull()) return false; std::stack<QQmlJSScope::ConstPtr> stack; stack.push(rootType); @@ -186,7 +186,7 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members, if (it == m_types.end()) { detectedRestrictiveKind = typeName; detectedRestrictiveName = access.m_name; - scope = nullptr; + scope = QQmlJSScope::ConstPtr(); } else { scope = *it; } @@ -304,7 +304,7 @@ bool CheckIdentifiers::operator()( auto it = qmlIDs.find(memberAccessBase.m_name); if (it != qmlIDs.end()) { - if (*it != nullptr) { + if (!it->isNull()) { if (!checkMemberAccess(memberAccessChain, *it)) noUnqualifiedIdentifier = false; continue; diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp index 62dce68bb7..962ccaa1c6 100644 --- a/tools/qmllint/findwarnings.cpp +++ b/tools/qmllint/findwarnings.cpp @@ -473,7 +473,7 @@ bool FindWarningVisitor::check() // now that all ids are known, revisit any Connections whose target were perviously unknown for (auto const &outstandingConnection: m_outstandingConnections) { auto targetScope = m_qmlid2scope[outstandingConnection.targetName]; - if (outstandingConnection.scope && targetScope != nullptr) + if (outstandingConnection.scope && !targetScope.isNull()) outstandingConnection.scope->addMethods(targetScope->methods()); QScopedValueRollback<QQmlJSScope::Ptr> rollback(m_currentScope, outstandingConnection.scope); outstandingConnection.uiod->initializer->accept(this); @@ -632,7 +632,7 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob) void FindWarningVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob) { - const auto childScope = m_currentScope; + const QQmlJSScope::ConstPtr childScope = m_currentScope; leaveEnvironment(); QQmlJSMetaProperty property(uiob->qualifiedId->name.toString(), uiob->qualifiedTypeNameId->name.toString(), @@ -736,7 +736,7 @@ void FindWarningVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *) const auto it = properties.find(QStringLiteral("parent")); if (it != properties.end()) { auto property = *it; - property.setType(m_currentScope); + property.setType(QQmlJSScope::ConstPtr(m_currentScope)); childScope->addProperty(property); } } |