forked from qt-creator/qt-creator
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:
@@ -27,6 +27,7 @@
|
|||||||
#include "qmldocumentparser.h"
|
#include "qmldocumentparser.h"
|
||||||
|
|
||||||
#include "projectstorage.h"
|
#include "projectstorage.h"
|
||||||
|
#include "projectstorageexceptions.h"
|
||||||
#include "sourcepathcache.h"
|
#include "sourcepathcache.h"
|
||||||
|
|
||||||
#include <sqlitedatabase.h>
|
#include <sqlitedatabase.h>
|
||||||
@@ -161,14 +162,33 @@ Storage::ImportedTypeName createImportedTypeName(const QStringView rawtypeName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void addPropertyDeclarations(Storage::Type &type,
|
void addPropertyDeclarations(Storage::Type &type,
|
||||||
const QmlDom::QmlObject &rootObject,
|
QmlDom::QmlObject &rootObject,
|
||||||
const QualifiedImports &qualifiedImports)
|
const QualifiedImports &qualifiedImports,
|
||||||
|
QmlDom::DomItem &fileItem)
|
||||||
{
|
{
|
||||||
for (const QmlDom::PropertyDefinition &propertyDeclaration : rootObject.propertyDefs()) {
|
for (const QmlDom::PropertyDefinition &propertyDeclaration : rootObject.propertyDefs()) {
|
||||||
type.propertyDeclarations.emplace_back(Utils::SmallString{propertyDeclaration.name},
|
if (propertyDeclaration.isAlias()) {
|
||||||
createImportedTypeName(propertyDeclaration.typeName,
|
auto rootObjectItem = fileItem.copy(&rootObject);
|
||||||
qualifiedImports),
|
auto property = rootObjectItem.bindings()
|
||||||
Storage::PropertyDeclarationTraits::None);
|
.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;
|
return type;
|
||||||
|
|
||||||
const auto &component = components.first();
|
const auto &component = components.first();
|
||||||
const auto &objects = component.objects();
|
auto objects = component.objects();
|
||||||
|
|
||||||
if (objects.empty())
|
if (objects.empty())
|
||||||
return type;
|
return type;
|
||||||
|
|
||||||
const QmlDom::QmlObject &qmlObject = objects.front();
|
QmlDom::QmlObject &qmlObject = objects.front();
|
||||||
|
|
||||||
const auto qmlImports = qmlFile->imports();
|
const auto qmlImports = qmlFile->imports();
|
||||||
|
|
||||||
@@ -274,7 +294,7 @@ Storage::Type QmlDocumentParser::parse(const QString &sourceContent,
|
|||||||
|
|
||||||
addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage);
|
addImports(imports, qmlFile->imports(), sourceId, directoryPath, m_storage);
|
||||||
|
|
||||||
addPropertyDeclarations(type, qmlObject, qualifiedImports);
|
addPropertyDeclarations(type, qmlObject, qualifiedImports, file);
|
||||||
addFunctionAndSignalDeclarations(type, qmlObject);
|
addFunctionAndSignalDeclarations(type, qmlObject);
|
||||||
addEnumeraton(type, component);
|
addEnumeraton(type, component);
|
||||||
|
|
||||||
|
@@ -59,6 +59,22 @@ MATCHER_P3(IsPropertyDeclaration,
|
|||||||
&& propertyDeclaration.traits == traits;
|
&& 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,
|
MATCHER_P2(IsFunctionDeclaration,
|
||||||
name,
|
name,
|
||||||
returnTypeName,
|
returnTypeName,
|
||||||
@@ -367,4 +383,75 @@ TEST_F(QmlDocumentParser, DISABLED_DuplicateImportsAreRemoved)
|
|||||||
Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
|
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
|
} // namespace
|
||||||
|
Reference in New Issue
Block a user