QmlDesigner: Alias support in the QmlDocumentParser

We have to adjust the storage to support indirect alias like:

Item {
  property alias textSize: foo.text.size
  Text{
    id: foo
  }
}
Task-number: QDS-7117
Change-Id: I0cf915ed710800dfa46ceff5d823e48ef45ec906

Change-Id: I11df6077ebbda208114b5e6f9c4eece611740096
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2022-05-18 16:33:43 +02:00
parent 4eade91d81
commit a9f9fac76d
2 changed files with 116 additions and 9 deletions

View File

@@ -27,6 +27,7 @@
#include "qmldocumentparser.h"
#include "projectstorage.h"
#include "projectstorageexceptions.h"
#include "sourcepathcache.h"
#include <sqlitedatabase.h>
@@ -161,14 +162,33 @@ Storage::ImportedTypeName createImportedTypeName(const QStringView rawtypeName,
}
void addPropertyDeclarations(Storage::Type &type,
const QmlDom::QmlObject &rootObject,
const QualifiedImports &qualifiedImports)
QmlDom::QmlObject &rootObject,
const QualifiedImports &qualifiedImports,
QmlDom::DomItem &fileItem)
{
for (const QmlDom::PropertyDefinition &propertyDeclaration : rootObject.propertyDefs()) {
type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name},
createImportedTypeName(propertyDeclaration.typeName,
qualifiedImports),
Storage::PropertyDeclarationTraits::None);
if (propertyDeclaration.isAlias()) {
auto rootObjectItem = fileItem.copy(&rootObject);
auto property = rootObjectItem.bindings()
.key(propertyDeclaration.name)
.index(0)
.field(QmlDom::Fields::value);
auto resolvedAlias = rootObject.resolveAlias(rootObjectItem,
property.ownerAs<QmlDom::ScriptExpression>());
if (resolvedAlias.valid()) {
type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name},
createImportedTypeName(resolvedAlias.typeName,
qualifiedImports),
Storage::PropertyDeclarationTraits::None,
Utils::SmallString{
resolvedAlias.accessedPath.join('.')});
}
} else {
type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name},
createImportedTypeName(propertyDeclaration.typeName,
qualifiedImports),
Storage::PropertyDeclarationTraits::None);
}
}
}
@@ -256,12 +276,12 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
return type;
const auto &component = components.first();
const auto &objects = component.objects();
auto objects = component.objects();
if (objects.empty())
return type;
const QmlDom::QmlObject &qmlObject = objects.front();
QmlDom::QmlObject &qmlObject = objects.front();
const auto qmlImports = qmlFile->imports();
@@ -274,7 +294,7 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage);
addPropertyDeclarations(type, qmlObject, qualifiedImports);
addPropertyDeclarations(type, qmlObject, qualifiedImports, file);
addFunctionAndSignalDeclarations(type, qmlObject);
addEnumeraton(type, component);

View File

@@ -59,6 +59,22 @@ MATCHER_P3(IsPropertyDeclaration,
&& propertyDeclaration.traits == traits;
}
MATCHER_P4(IsAliasPropertyDeclaration,
name,
typeName,
traits,
aliasPropertyName,
std::string(negation ? "isn't " : "is ")
+ PrintToString(Storage::PropertyDeclaration{name, typeName, traits, aliasPropertyName}))
{
const Storage::PropertyDeclaration &propertyDeclaration = arg;
return propertyDeclaration.name == name
&& Storage::ImportedTypeName{typeName} == propertyDeclaration.typeName
&& propertyDeclaration.traits == traits
&& propertyDeclaration.aliasPropertyName == aliasPropertyName;
}
MATCHER_P2(IsFunctionDeclaration,
name,
returnTypeName,
@@ -367,4 +383,75 @@ TEST_F(QmlDocumentParser, DISABLED_DuplicateImportsAreRemoved)
Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
}
TEST_F(QmlDocumentParser, AliasItemProperties)
{
auto type = parser.parse(R"(Example{
property alias delegate: foo
Item {
id: foo
}
})",
imports,
qmlFileSourceId,
directoryPath);
ASSERT_THAT(type.propertyDeclarations,
UnorderedElementsAre(IsPropertyDeclaration("delegate",
Storage::ImportedType{"Item"},
Storage::PropertyDeclarationTraits::None)));
}
TEST_F(QmlDocumentParser, AliasProperties)
{
auto type = parser.parse(R"(Example{
property alias text: foo.text2
Item {
id: foo
}
})",
imports,
qmlFileSourceId,
directoryPath);
ASSERT_THAT(type.propertyDeclarations,
UnorderedElementsAre(IsAliasPropertyDeclaration("text",
Storage::ImportedType{"Item"},
Storage::PropertyDeclarationTraits::None,
"text2")));
}
TEST_F(QmlDocumentParser, IndirectAliasProperties)
{
auto type = parser.parse(R"(Example{
property alias textSize: foo.text.size
Item {
id: foo
}
})",
imports,
qmlFileSourceId,
directoryPath);
ASSERT_THAT(type.propertyDeclarations,
UnorderedElementsAre(IsAliasPropertyDeclaration("textSize",
Storage::ImportedType{"Item"},
Storage::PropertyDeclarationTraits::None,
"text.size")));
}
TEST_F(QmlDocumentParser, InvalidAliasPropertiesAreSkipped)
{
auto type = parser.parse(R"(Example{
property alias textSize: foo2.text.size
Item {
id: foo
}
})",
imports,
qmlFileSourceId,
directoryPath);
ASSERT_THAT(type.propertyDeclarations, IsEmpty());
}
} // namespace