QQmlJSScope: Decouple ContextualTypes

ContextualTypes are required in the import visitor logic, but they
aren't actually used directly inside QQmlJSScope.

Change-Id: I5cd49076687ef97c1077678c8dc757cde3b94c51
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Reviewed-by: Sami Shalayel <sami.shalayel@qt.io>
Reviewed-by: Semih Yavuz <semih.yavuz@qt.io>
This commit is contained in:
Fabian Kosmale 2023-08-01 15:43:15 +02:00
parent 4bf10f9f9c
commit 5461b90cda
8 changed files with 122 additions and 89 deletions

View File

@ -30,6 +30,7 @@ qt_internal_add_module(QmlCompilerPrivate
qqmljsresourcefilemapper.cpp qqmljsresourcefilemapper_p.h
qqmljsscope.cpp qqmljsscope_p.h
qqmljsscopesbyid_p.h
qqmljscontextualtypes_p.h
qqmljsshadowcheck.cpp qqmljsshadowcheck_p.h
qqmljsstoragegeneralizer.cpp qqmljsstoragegeneralizer_p.h
qqmljstypedescriptionreader.cpp qqmljstypedescriptionreader_p.h

View File

@ -0,0 +1,91 @@
// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QQMLJSCONTEXTUALTYPES_P_H
#define QQMLJSCONTEXTUALTYPES_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/qstring.h>
#include <QtCore/qhash.h>
#include <private/qqmljsscope_p.h>
QT_BEGIN_NAMESPACE
namespace QQmlJS {
/*! \internal
* Maps type names to types and the compile context of the types. The context can be
* INTERNAL (for c++ and synthetic jsrootgen types) or QML (for qml types).
*/
struct ContextualTypes
{
enum CompileContext { INTERNAL, QML };
ContextualTypes(
CompileContext context,
const QHash<QString, ImportedScope<QQmlJSScope::ConstPtr>> types,
const QQmlJSScope::ConstPtr &arrayType)
: m_types(types)
, m_context(context)
, m_arrayType(arrayType)
{}
CompileContext context() const { return m_context; }
QQmlJSScope::ConstPtr arrayType() const { return m_arrayType; }
bool hasType(const QString &name) const { return m_types.contains(name); }
ImportedScope<QQmlJSScope::ConstPtr> type(const QString &name) const { return m_types[name]; }
void setType(const QString &name, const ImportedScope<QQmlJSScope::ConstPtr> &type)
{
m_types.insert(name, type);
}
void clearType(const QString &name)
{
m_types[name].scope = QQmlJSScope::ConstPtr();
}
bool isNullType(const QString &name) const
{
const auto it = m_types.constFind(name);
return it != m_types.constEnd() && it->scope.isNull();
}
void addTypes(ContextualTypes &&types)
{
Q_ASSERT(types.m_context == m_context);
m_types.insert(std::move(types.m_types));
}
void addTypes(const ContextualTypes &types)
{
Q_ASSERT(types.m_context == m_context);
m_types.insert(types.m_types);
}
const QHash<QString, ImportedScope<QQmlJSScope::ConstPtr>> &types() const { return m_types; }
void clearTypes() { m_types.clear(); }
private:
QHash<QString, ImportedScope<QQmlJSScope::ConstPtr>> m_types;
CompileContext m_context;
// For resolving enums
QQmlJSScope::ConstPtr m_intType;
// For resolving sequence types
QQmlJSScope::ConstPtr m_arrayType;
};
}
QT_END_NAMESPACE
#endif // QQMLJSCONTEXTUALTYPES_P_H

View File

@ -16,6 +16,7 @@
#include <private/qtqmlcompilerexports_p.h>
#include "qqmljscontextualtypes_p.h"
#include "qqmljsscope_p.h"
#include "qqmljsresourcefilemapper_p.h"
#include <QtQml/private/qqmldirparser_p.h>
@ -29,7 +30,7 @@ class QQmlJSLogger;
class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSImporter
{
public:
using ImportedTypes = QQmlJSScope::ContextualTypes;
using ImportedTypes = QQmlJS::ContextualTypes;
QQmlJSImporter(const QStringList &importPaths, QQmlJSResourceFileMapper *mapper,
bool useOptionalImports = false);
@ -92,7 +93,7 @@ private:
{
AvailableTypes(ImportedTypes builtins)
: cppNames(std::move(builtins))
, qmlNames(QQmlJSScope::ContextualTypes::QML, {}, cppNames.arrayType())
, qmlNames(QQmlJS::ContextualTypes::QML, {}, cppNames.arrayType())
{
}

View File

@ -366,7 +366,7 @@ void QQmlJSImportVisitor::importBaseModules()
// Pulling in the modules and neighboring qml files of the qmltypes we're trying to lint is not
// something we need to do.
if (!m_logger->fileName().endsWith(u".qmltypes"_s)) {
QQmlJSScope::ContextualTypes fromDirectory =
QQmlJS::ContextualTypes fromDirectory =
m_importer->importDirectory(m_implicitImportDirectory);
m_rootScopeImports.addTypes(std::move(fromDirectory));

View File

@ -14,6 +14,7 @@
//
// We mean it.
#include <private/qqmljscontextualtypes_p.h>
#include <private/qtqmlcompilerexports_p.h>
#include "qqmljsannotation_p.h"

View File

@ -1,6 +1,7 @@
// Copyright (C) 2019 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "qqmljscontextualtypes_p.h"
#include "qqmljsscope_p.h"
#include "qqmljstypereader_p.h"
#include "qqmljsimporter_p.h"
@ -379,7 +380,7 @@ std::optional<QQmlJSScope::JavaScriptIdentifier> QQmlJSScope::JSIdentifier(const
}
static QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr>
qFindInlineComponents(QStringView typeName, const QQmlJSScope::ContextualTypes &contextualTypes)
qFindInlineComponents(QStringView typeName, const QQmlJS::ContextualTypes &contextualTypes)
{
const int separatorIndex = typeName.lastIndexOf(u'.');
// do not crash in typeName.sliced() when it starts or ends with an '.'.
@ -424,7 +425,7 @@ qFindInlineComponents(QStringView typeName, const QQmlJSScope::ContextualTypes &
* ("qmlFileName.IC" is correctly resolved from qmlFileName).
*/
QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
const QString &name, const QQmlJSScope::ContextualTypes &contextualTypes,
const QString &name, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes)
{
const auto useType = [&]() {
@ -457,7 +458,7 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
};
switch (contextualTypes.context()) {
case ContextualTypes::INTERNAL: {
case QQmlJS::ContextualTypes::INTERNAL: {
if (const auto listType = findListType(u"QList<"_s, u">"_s);
listType.scope && !listType.scope->isReferenceType()) {
return listType;
@ -487,7 +488,7 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
break;
}
case ContextualTypes::QML: {
case QQmlJS::ContextualTypes::QML: {
// look after inline components
const auto inlineComponent = qFindInlineComponents(name, contextualTypes);
if (inlineComponent.scope) {
@ -505,7 +506,7 @@ QQmlJSScope::ImportedScope<QQmlJSScope::ConstPtr> QQmlJSScope::findType(
}
QTypeRevision QQmlJSScope::resolveType(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &context,
const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &context,
QSet<QString> *usedTypes)
{
if (self->accessSemantics() == AccessSemantics::Sequence
@ -593,7 +594,7 @@ QTypeRevision QQmlJSScope::resolveType(
void QQmlJSScope::updateChildScope(
const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
switch (childScope->scopeType()) {
case QQmlSA::ScopeType::GroupedPropertyScope:
@ -627,7 +628,7 @@ void QQmlJSScope::updateChildScope(
template<typename Resolver, typename ChildScopeUpdater>
static QTypeRevision resolveTypesInternal(
Resolver resolve, ChildScopeUpdater update, const QQmlJSScope::Ptr &self,
const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
const QTypeRevision revision = resolve(self, contextualTypes, usedTypes);
// NB: constness ensures no detach
@ -641,11 +642,11 @@ static QTypeRevision resolveTypesInternal(
}
QTypeRevision QQmlJSScope::resolveTypes(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes)
{
const auto resolveAll = [](const QQmlJSScope::Ptr &self,
const QQmlJSScope::ContextualTypes &contextualTypes,
const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes) {
resolveEnums(self, contextualTypes, usedTypes);
resolveList(self, contextualTypes.arrayType());
@ -655,7 +656,7 @@ QTypeRevision QQmlJSScope::resolveTypes(
}
void QQmlJSScope::resolveNonEnumTypes(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes)
{
resolveTypesInternal(resolveType, updateChildScope, self, contextualTypes, usedTypes);
@ -696,7 +697,7 @@ static QString flagStorage(const QString &underlyingType)
does not have an enum called like the alias.
*/
void QQmlJSScope::resolveEnums(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes)
{
// temporary hash to avoid messing up m_enumerations while iterators are active on it
@ -758,8 +759,8 @@ void QQmlJSScope::resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::C
const QQmlJSImportedScope element = {self, QTypeRevision()};
const QQmlJSImportedScope array = {arrayType, QTypeRevision()};
QQmlJSScope::ContextualTypes contextualTypes(
QQmlJSScope::ContextualTypes::INTERNAL, { { self->internalName(), element }, },
QQmlJS::ContextualTypes contextualTypes(
QQmlJS::ContextualTypes::INTERNAL, { { self->internalName(), element }, },
arrayType);
QQmlJSScope::resolveTypes(listType, contextualTypes);
@ -769,7 +770,7 @@ void QQmlJSScope::resolveList(const QQmlJSScope::Ptr &self, const QQmlJSScope::C
void QQmlJSScope::resolveGeneralizedGroup(
const Ptr &self, const ConstPtr &baseType,
const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes)
{
Q_ASSERT(baseType);
// Generalized group properties are always composite,

View File

@ -157,6 +157,8 @@ struct ImportedScope {
QTypeRevision revision;
};
struct ContextualTypes;
} // namespace QQmlJS
class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSScope
@ -208,70 +210,6 @@ public:
template <typename Pointer>
using ExportedScope = QQmlJS::ExportedScope<Pointer>;
/*! \internal
* Maps type names to types and the compile context of the types. The context can be
* INTERNAl (for c++ and synthetic jsrootgen types) or QML (for qml types).
*/
struct ContextualTypes
{
enum CompileContext { INTERNAL, QML };
ContextualTypes(
CompileContext context,
const QHash<QString, ImportedScope<ConstPtr>> types,
const QQmlJSScope::ConstPtr &arrayType)
: m_types(types)
, m_context(context)
, m_arrayType(arrayType)
{}
CompileContext context() const { return m_context; }
ConstPtr arrayType() const { return m_arrayType; }
bool hasType(const QString &name) const { return m_types.contains(name); }
ImportedScope<ConstPtr> type(const QString &name) const { return m_types[name]; }
void setType(const QString &name, const ImportedScope<ConstPtr> &type)
{
m_types.insert(name, type);
}
void clearType(const QString &name)
{
m_types[name].scope = QQmlJSScope::ConstPtr();
}
bool isNullType(const QString &name) const
{
const auto it = m_types.constFind(name);
return it != m_types.constEnd() && it->scope.isNull();
}
void addTypes(ContextualTypes &&types)
{
Q_ASSERT(types.m_context == m_context);
m_types.insert(std::move(types.m_types));
}
void addTypes(const ContextualTypes &types)
{
Q_ASSERT(types.m_context == m_context);
m_types.insert(types.m_types);
}
const QHash<QString, ImportedScope<ConstPtr>> &types() const { return m_types; }
void clearTypes() { m_types.clear(); }
private:
QHash<QString, ImportedScope<ConstPtr>> m_types;
CompileContext m_context;
// For resolving enums
QQmlJSScope::ConstPtr m_intType;
// For resolving sequence types
QQmlJSScope::ConstPtr m_arrayType;
};
struct JavaScriptIdentifier
{
enum Kind {
@ -516,19 +454,19 @@ public:
QVector<QQmlJSScope::ConstPtr> childScopes() const;
static QTypeRevision resolveTypes(
const Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
const Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes = nullptr);
static void resolveNonEnumTypes(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes = nullptr);
static void resolveEnums(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ContextualTypes &contextualTypes,
const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes = nullptr);
static void resolveList(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &arrayType);
static void resolveGeneralizedGroup(
const QQmlJSScope::Ptr &self, const QQmlJSScope::ConstPtr &baseType,
const QQmlJSScope::ContextualTypes &contextualTypes,
const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes = nullptr);
void setSourceLocation(const QQmlJS::SourceLocation &sourceLocation);
@ -562,7 +500,7 @@ public:
};
static ImportedScope<QQmlJSScope::ConstPtr> findType(const QString &name,
const ContextualTypes &contextualTypes,
const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes = nullptr);
static QQmlSA::Element createQQmlSAElement(const ConstPtr &);
@ -575,11 +513,11 @@ private:
QQmlJSScope(const QQmlJSScope &) = default;
QQmlJSScope &operator=(const QQmlJSScope &) = default;
static QTypeRevision resolveType(
const QQmlJSScope::Ptr &self, const ContextualTypes &contextualTypes,
const QQmlJSScope::Ptr &self, const QQmlJS::ContextualTypes &contextualTypes,
QSet<QString> *usedTypes);
static void updateChildScope(
const QQmlJSScope::Ptr &childScope, const QQmlJSScope::Ptr &self,
const QQmlJSScope::ContextualTypes &contextualTypes, QSet<QString> *usedTypes);
const QQmlJS::ContextualTypes &contextualTypes, QSet<QString> *usedTypes);
void addOwnPropertyBindingInQmlIROrder(const QQmlJSMetaPropertyBinding &binding,
BindingTargetSpecifier specifier);

View File

@ -208,7 +208,7 @@ void tst_qqmljsscope::allTypesAvailable()
QQmlJSImporter importer { importPaths, /* resource file mapper */ nullptr };
const auto imported = importer.importModule(u"QtQml"_s);
QCOMPARE(imported.context(), QQmlJSScope::ContextualTypes::QML);
QCOMPARE(imported.context(), QQmlJS::ContextualTypes::QML);
const auto types = imported.types();
QVERIFY(types.contains(u"$internal$.QObject"_s));
QVERIFY(types.contains(u"QtObject"_s));