QmlDesigner: Support qualified prototypes in the qml document parser

Task-number: QDS-6191
Change-Id: I459d09df4ed0ba901fd4f214dd3de81556ee7896
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Marco Bubke
2022-02-10 16:48:13 +01:00
parent 59d9a2dcdc
commit 6e9cb8ad54
2 changed files with 78 additions and 20 deletions

View File

@@ -41,6 +41,8 @@ namespace QmlDom = QQmlJS::Dom;
namespace {
using QualifiedImports = std::map<QString, Storage::Import>;
int convertVersionNumber(qint32 versionNumber)
{
return versionNumber < 0 ? -1 : versionNumber;
@@ -64,24 +66,49 @@ Utils::PathString convertUri(const QString &uri)
return Utils::PathString{x.generic_string()};
}
Storage::Import createImport(const QmlDom::Import &qmlImport,
SourceId sourceId,
Utils::SmallStringView directoryPath,
QmlDocumentParser::ProjectStorage &storage)
{
if (qmlImport.uri == u"file://.") {
auto moduleId = storage.moduleId(directoryPath);
return Storage::Import(moduleId, Storage::Version{}, sourceId);
}
if (qmlImport.uri.startsWith(u"file://")) {
auto moduleId = storage.moduleId(convertUri(qmlImport.uri));
return Storage::Import(moduleId, Storage::Version{}, sourceId);
}
auto moduleId = storage.moduleId(Utils::SmallString{qmlImport.uri});
return Storage::Import(moduleId, convertVersion(qmlImport.version), sourceId);
}
QualifiedImports filterQualifiedImports(const QList<QmlDom::Import> &qmlImports,
SourceId sourceId,
Utils::SmallStringView directoryPath,
QmlDocumentParser::ProjectStorage &storage)
{
QualifiedImports qualifiedImports;
for (const QmlDom::Import &qmlImport : qmlImports) {
if (!qmlImport.importId.isEmpty())
qualifiedImports.try_emplace(qmlImport.importId,
createImport(qmlImport, sourceId, directoryPath, storage));
}
return qualifiedImports;
}
void addImports(Storage::Imports &imports,
const QList<QmlDom::Import> &qmlImports,
SourceId sourceId,
Utils::SmallStringView directoryPath,
QmlDocumentParser::ProjectStorage &storage)
{
for (const QmlDom::Import &qmlImport : qmlImports) {
if (qmlImport.uri == u"file://.") {
auto moduleId = storage.moduleId(directoryPath);
imports.emplace_back(moduleId, Storage::Version{}, sourceId);
} else if (qmlImport.uri.startsWith(u"file://")) {
auto moduleId = storage.moduleId(convertUri(qmlImport.uri));
imports.emplace_back(moduleId, Storage::Version{}, sourceId);
} else {
auto moduleId = storage.moduleId(Utils::SmallString{qmlImport.uri});
imports.emplace_back(moduleId, convertVersion(qmlImport.version), sourceId);
}
}
for (const QmlDom::Import &qmlImport : qmlImports)
imports.push_back(createImport(qmlImport, sourceId, directoryPath, storage));
auto end = imports.end();
auto begin = std::prev(end, qmlImports.size());
@@ -90,6 +117,30 @@ void addImports(Storage::Imports &imports,
imports.erase(std::unique(begin, end), end);
}
Storage::ImportedTypeName createImportedTypeName(const QStringView rawtypeName,
const QList<QmlDom::Import> &qmlImports,
SourceId sourceId,
Utils::SmallStringView directoryPath,
QmlDocumentParser::ProjectStorage &storage)
{
if (!rawtypeName.contains('.')) {
return Storage::ImportedType{Utils::SmallString{rawtypeName}};
}
auto qualifiedImports = filterQualifiedImports(qmlImports, sourceId, directoryPath, storage);
auto foundDot = std::find(rawtypeName.begin(), rawtypeName.end(), '.');
QStringView alias(rawtypeName.begin(), foundDot);
auto foundImport = qualifiedImports.find(alias.toString());
QStringView typeName(std::next(foundDot), rawtypeName.end());
return Storage::QualifiedImportedType{Utils::SmallString{typeName.toString()},
foundImport->second};
}
void addPropertyDeclarations(Storage::Type &type, const QmlDom::QmlObject &rootObject)
{
for (const QmlDom::PropertyDefinition &propertyDeclaration : rootObject.propertyDefs()) {
@@ -188,10 +239,15 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
const QmlDom::QmlObject &qmlObject = objects.front();
type.prototype = Storage::ImportedType{Utils::SmallString{qmlObject.name()}};
const auto qmlImports = qmlFile->imports();
auto directoryPath{m_pathCache.sourceContextPath(m_pathCache.sourceContextId(sourceId))};
type.prototype = createImportedTypeName(qmlObject.name(),
qmlImports,
sourceId,
directoryPath,
m_storage);
addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage);
addPropertyDeclarations(type, qmlObject);

View File

@@ -143,17 +143,19 @@ TEST_F(QmlDocumentParser, Prototype)
ASSERT_THAT(type, HasPrototype(Storage::ImportedType("Example")));
}
TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype)
TEST_F(QmlDocumentParser, QualifiedPrototype)
{
auto exampleModuleId = storage.moduleId("Example");
QString text = R"(import Example as Example
Example.Item{})";
QString text = R"(import Example 2.1 as Example
Example.Item{})";
auto type = parser.parse(text, imports, qmlFileSourceId);
ASSERT_THAT(type,
HasPrototype(Storage::QualifiedImportedType(
"Item", Storage::Import{exampleModuleId, Storage::Version{}, qmlFileSourceId})));
HasPrototype(Storage::QualifiedImportedType("Item",
Storage::Import{exampleModuleId,
Storage::Version{2, 1},
qmlFileSourceId})));
}
TEST_F(QmlDocumentParser, Properties)