forked from qt-creator/qt-creator
QmlDesigner: Lookup the default property in prototypes too
The default property can be set too in any prototypes. Look them up there too. Because it is expensive we cache them in the node meta info to make hasDefaultProperty() followed by defaultProperty() cheaper. Change-Id: I3b9ec90fc1bc5f0228dad3b580c335734f03821d Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: Qt CI Patch Build Bot <ci_patchbuild_bot@qt.io>
This commit is contained in:
@@ -265,12 +265,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const Storage::Info::Type &typeData() const;
|
const Storage::Info::Type &typeData() const;
|
||||||
|
PropertyDeclarationId defaultPropertyDeclarationId() const;
|
||||||
bool isSubclassOf(const TypeName &type, int majorVersion = -1, int minorVersion = -1) const;
|
bool isSubclassOf(const TypeName &type, int majorVersion = -1, int minorVersion = -1) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypeId m_typeId;
|
TypeId m_typeId;
|
||||||
NotNullPointer<const ProjectStorageType> m_projectStorage = {};
|
NotNullPointer<const ProjectStorageType> m_projectStorage = {};
|
||||||
mutable std::optional<Storage::Info::Type> m_typeData;
|
mutable std::optional<Storage::Info::Type> m_typeData;
|
||||||
|
mutable std::optional<PropertyDeclarationId> m_defaultPropertyId;
|
||||||
std::shared_ptr<NodeMetaInfoPrivate> m_privateData;
|
std::shared_ptr<NodeMetaInfoPrivate> m_privateData;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -1835,7 +1835,7 @@ PropertyName NodeMetaInfo::defaultPropertyName() const
|
|||||||
{
|
{
|
||||||
if constexpr (useProjectStorage()) {
|
if constexpr (useProjectStorage()) {
|
||||||
if (isValid()) {
|
if (isValid()) {
|
||||||
if (auto name = m_projectStorage->propertyName(typeData().defaultPropertyId)) {
|
if (auto name = m_projectStorage->propertyName(defaultPropertyDeclarationId())) {
|
||||||
return name->toQByteArray();
|
return name->toQByteArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1851,7 +1851,7 @@ PropertyMetaInfo NodeMetaInfo::defaultProperty() const
|
|||||||
{
|
{
|
||||||
if constexpr (useProjectStorage()) {
|
if constexpr (useProjectStorage()) {
|
||||||
if (isValid()) {
|
if (isValid()) {
|
||||||
return PropertyMetaInfo(typeData().defaultPropertyId, m_projectStorage);
|
return PropertyMetaInfo(defaultPropertyDeclarationId(), m_projectStorage);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return property(defaultPropertyName());
|
return property(defaultPropertyName());
|
||||||
@@ -1862,7 +1862,7 @@ PropertyMetaInfo NodeMetaInfo::defaultProperty() const
|
|||||||
bool NodeMetaInfo::hasDefaultProperty() const
|
bool NodeMetaInfo::hasDefaultProperty() const
|
||||||
{
|
{
|
||||||
if constexpr (useProjectStorage())
|
if constexpr (useProjectStorage())
|
||||||
return isValid() && bool(typeData().defaultPropertyId);
|
return isValid() && bool(defaultPropertyDeclarationId());
|
||||||
else
|
else
|
||||||
return !defaultPropertyName().isEmpty();
|
return !defaultPropertyName().isEmpty();
|
||||||
}
|
}
|
||||||
@@ -2089,6 +2089,14 @@ const Storage::Info::Type &NodeMetaInfo::typeData() const
|
|||||||
return *m_typeData;
|
return *m_typeData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PropertyDeclarationId NodeMetaInfo::defaultPropertyDeclarationId() const
|
||||||
|
{
|
||||||
|
if (!m_defaultPropertyId)
|
||||||
|
m_defaultPropertyId = m_projectStorage->defaultPropertyDeclarationId(m_typeId);
|
||||||
|
|
||||||
|
return *m_defaultPropertyId;
|
||||||
|
}
|
||||||
|
|
||||||
bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int minorVersion) const
|
bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int minorVersion) const
|
||||||
{
|
{
|
||||||
if (!isValid()) {
|
if (!isValid()) {
|
||||||
|
@@ -408,6 +408,22 @@ public:
|
|||||||
return propertyDeclarationId;
|
return propertyDeclarationId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const override
|
||||||
|
{
|
||||||
|
using NanotraceHR::keyValue;
|
||||||
|
NanotraceHR::Tracer tracer{"get default property declaration id"_t,
|
||||||
|
projectStorageCategory(),
|
||||||
|
keyValue("type id", typeId)};
|
||||||
|
|
||||||
|
auto propertyDeclarationId = Sqlite::withDeferredTransaction(database, [&] {
|
||||||
|
return fetchDefaultPropertyDeclarationId(typeId);
|
||||||
|
});
|
||||||
|
|
||||||
|
tracer.end(keyValue("property declaration id", propertyDeclarationId));
|
||||||
|
|
||||||
|
return propertyDeclarationId;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<Storage::Info::PropertyDeclaration> propertyDeclaration(
|
std::optional<Storage::Info::PropertyDeclaration> propertyDeclaration(
|
||||||
PropertyDeclarationId propertyDeclarationId) const override
|
PropertyDeclarationId propertyDeclarationId) const override
|
||||||
{
|
{
|
||||||
@@ -2379,17 +2395,42 @@ private:
|
|||||||
return PropertyDeclarationId{};
|
return PropertyDeclarationId{};
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyDeclarationId fetchPropertyDeclarationId(TypeId baseTypeId,
|
PropertyDeclarationId fetchPropertyDeclarationId(TypeId typeId,
|
||||||
Utils::SmallStringView propertyName) const
|
Utils::SmallStringView propertyName) const
|
||||||
{
|
{
|
||||||
auto propertyDeclarationId = selectPropertyDeclarationIdByTypeIdAndNameStatement
|
auto propertyDeclarationId = selectPropertyDeclarationIdByTypeIdAndNameStatement
|
||||||
.template value<PropertyDeclarationId>(baseTypeId,
|
.template value<PropertyDeclarationId>(typeId, propertyName);
|
||||||
propertyName);
|
|
||||||
|
|
||||||
if (propertyDeclarationId)
|
if (propertyDeclarationId)
|
||||||
return propertyDeclarationId;
|
return propertyDeclarationId;
|
||||||
|
|
||||||
return fetchNextPropertyDeclarationId(baseTypeId, propertyName);
|
return fetchNextPropertyDeclarationId(typeId, propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyDeclarationId fetchNextDefaultPropertyDeclarationId(TypeId baseTypeId) const
|
||||||
|
{
|
||||||
|
auto range = selectPrototypeAndExtensionIdsStatement.template range<TypeId>(baseTypeId);
|
||||||
|
|
||||||
|
for (TypeId prototype : range) {
|
||||||
|
auto propertyDeclarationId = selectDefaultPropertyDeclarationIdStatement
|
||||||
|
.template value<PropertyDeclarationId>(prototype);
|
||||||
|
|
||||||
|
if (propertyDeclarationId)
|
||||||
|
return propertyDeclarationId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PropertyDeclarationId{};
|
||||||
|
}
|
||||||
|
|
||||||
|
PropertyDeclarationId fetchDefaultPropertyDeclarationId(TypeId typeId) const
|
||||||
|
{
|
||||||
|
auto propertyDeclarationId = selectDefaultPropertyDeclarationIdStatement
|
||||||
|
.template value<PropertyDeclarationId>(typeId);
|
||||||
|
|
||||||
|
if (propertyDeclarationId)
|
||||||
|
return propertyDeclarationId;
|
||||||
|
|
||||||
|
return fetchNextDefaultPropertyDeclarationId(typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void synchronizePropertyDeclarationsInsertProperty(
|
void synchronizePropertyDeclarationsInsertProperty(
|
||||||
@@ -4842,9 +4883,10 @@ public:
|
|||||||
"UPDATE types SET defaultPropertyId=?2 WHERE typeId=?1", database};
|
"UPDATE types SET defaultPropertyId=?2 WHERE typeId=?1", database};
|
||||||
WriteStatement<1> updateDefaultPropertyIdToNullStatement{
|
WriteStatement<1> updateDefaultPropertyIdToNullStatement{
|
||||||
"UPDATE types SET defaultPropertyId=NULL WHERE defaultPropertyId=?1", database};
|
"UPDATE types SET defaultPropertyId=NULL WHERE defaultPropertyId=?1", database};
|
||||||
mutable ReadStatement<4, 1> selectInfoTypeByTypeIdStatement{
|
mutable ReadStatement<3, 1> selectInfoTypeByTypeIdStatement{
|
||||||
"SELECT defaultPropertyId, sourceId, traits, annotationTraits FROM types WHERE typeId=?",
|
"SELECT sourceId, traits, annotationTraits FROM types WHERE typeId=?", database};
|
||||||
database};
|
mutable ReadStatement<1, 1> selectDefaultPropertyDeclarationIdStatement{
|
||||||
|
"SELECT defaultPropertyId FROM types WHERE typeId=?", database};
|
||||||
mutable ReadStatement<1, 1> selectPrototypeIdsForTypeIdInOrderStatement{
|
mutable ReadStatement<1, 1> selectPrototypeIdsForTypeIdInOrderStatement{
|
||||||
"WITH RECURSIVE "
|
"WITH RECURSIVE "
|
||||||
" all_prototype_and_extension(typeId, prototypeId) AS ("
|
" all_prototype_and_extension(typeId, prototypeId) AS ("
|
||||||
|
@@ -503,18 +503,13 @@ public:
|
|||||||
class Type
|
class Type
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type(PropertyDeclarationId defaultPropertyId,
|
Type(SourceId sourceId, long long typeTraits, long long typeAnnotationTraits)
|
||||||
SourceId sourceId,
|
: sourceId{sourceId}
|
||||||
long long typeTraits,
|
|
||||||
long long typeAnnotationTraits)
|
|
||||||
: defaultPropertyId{defaultPropertyId}
|
|
||||||
, sourceId{sourceId}
|
|
||||||
, traits{typeTraits, typeAnnotationTraits}
|
, traits{typeTraits, typeAnnotationTraits}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Type(PropertyDeclarationId defaultPropertyId, SourceId sourceId, TypeTraits traits)
|
Type(SourceId sourceId, TypeTraits traits)
|
||||||
: defaultPropertyId{defaultPropertyId}
|
: sourceId{sourceId}
|
||||||
, sourceId{sourceId}
|
|
||||||
, traits{traits}
|
, traits{traits}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@@ -523,14 +518,11 @@ public:
|
|||||||
{
|
{
|
||||||
using NanotraceHR::dictonary;
|
using NanotraceHR::dictonary;
|
||||||
using NanotraceHR::keyValue;
|
using NanotraceHR::keyValue;
|
||||||
auto dict = dictonary(keyValue("default property id", type.defaultPropertyId),
|
auto dict = dictonary(keyValue("source id", type.sourceId), keyValue("traits", type.traits));
|
||||||
keyValue("source id", type.sourceId),
|
|
||||||
keyValue("traits", type.traits));
|
|
||||||
|
|
||||||
convertToString(string, dict);
|
convertToString(string, dict);
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyDeclarationId defaultPropertyId;
|
|
||||||
SourceId sourceId;
|
SourceId sourceId;
|
||||||
TypeTraits traits;
|
TypeTraits traits;
|
||||||
};
|
};
|
||||||
|
@@ -55,6 +55,7 @@ public:
|
|||||||
virtual PropertyDeclarationId propertyDeclarationId(TypeId typeId,
|
virtual PropertyDeclarationId propertyDeclarationId(TypeId typeId,
|
||||||
::Utils::SmallStringView propertyName) const
|
::Utils::SmallStringView propertyName) const
|
||||||
= 0;
|
= 0;
|
||||||
|
virtual PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const = 0;
|
||||||
virtual std::optional<Storage::Info::Type> type(TypeId typeId) const = 0;
|
virtual std::optional<Storage::Info::Type> type(TypeId typeId) const = 0;
|
||||||
virtual Utils::PathString typeIconPath(TypeId typeId) const = 0;
|
virtual Utils::PathString typeIconPath(TypeId typeId) const = 0;
|
||||||
virtual Storage::Info::TypeHints typeHints(TypeId typeId) const = 0;
|
virtual Storage::Info::TypeHints typeHints(TypeId typeId) const = 0;
|
||||||
|
@@ -293,8 +293,10 @@ TypeId ProjectStorageMock::createType(ModuleId moduleId,
|
|||||||
defaultPropertyTypeId);
|
defaultPropertyTypeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ON_CALL(*this, type(Eq(typeId)))
|
ON_CALL(*this, type(Eq(typeId))).WillByDefault(Return(Storage::Info::Type{sourceId, typeTraits}));
|
||||||
.WillByDefault(Return(Storage::Info::Type{defaultPropertyDeclarationId, sourceId, typeTraits}));
|
|
||||||
|
ON_CALL(*this, defaultPropertyDeclarationId(Eq(typeId)))
|
||||||
|
.WillByDefault(Return(defaultPropertyDeclarationId));
|
||||||
|
|
||||||
ON_CALL(*this, isBasedOn(Eq(typeId), Eq(typeId))).WillByDefault(Return(true));
|
ON_CALL(*this, isBasedOn(Eq(typeId), Eq(typeId))).WillByDefault(Return(true));
|
||||||
|
|
||||||
|
@@ -187,6 +187,10 @@ public:
|
|||||||
propertyDeclarationId,
|
propertyDeclarationId,
|
||||||
(QmlDesigner::TypeId typeId, ::Utils::SmallStringView propertyName),
|
(QmlDesigner::TypeId typeId, ::Utils::SmallStringView propertyName),
|
||||||
(const, override));
|
(const, override));
|
||||||
|
MOCK_METHOD(QmlDesigner::PropertyDeclarationId,
|
||||||
|
defaultPropertyDeclarationId,
|
||||||
|
(QmlDesigner::TypeId typeId),
|
||||||
|
(const, override));
|
||||||
MOCK_METHOD(std::optional<QmlDesigner::Storage::Info::Type>,
|
MOCK_METHOD(std::optional<QmlDesigner::Storage::Info::Type>,
|
||||||
type,
|
type,
|
||||||
(QmlDesigner::TypeId typeId),
|
(QmlDesigner::TypeId typeId),
|
||||||
|
@@ -675,7 +675,7 @@ std::ostream &operator<<(std::ostream &out, const PropertyDeclaration &propertyD
|
|||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const Type &type)
|
std::ostream &operator<<(std::ostream &out, const Type &type)
|
||||||
{
|
{
|
||||||
return out << "(" << type.defaultPropertyId << ")";
|
return out << "(" << type.sourceId << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream &operator<<(std::ostream &out, const ExportedTypeName &name)
|
std::ostream &operator<<(std::ostream &out, const ExportedTypeName &name)
|
||||||
|
@@ -61,8 +61,8 @@ protected:
|
|||||||
++defaultPropertyIdNumber);
|
++defaultPropertyIdNumber);
|
||||||
|
|
||||||
ON_CALL(projectStorageMock, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId));
|
ON_CALL(projectStorageMock, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId));
|
||||||
ON_CALL(projectStorageMock, type(Eq(typeId)))
|
ON_CALL(projectStorageMock, defaultPropertyDeclarationId(Eq(typeId)))
|
||||||
.WillByDefault(Return(Info::Type{defaultPropertyId, QmlDesigner::SourceId{}, {}}));
|
.WillByDefault(Return(defaultPropertyId));
|
||||||
ON_CALL(projectStorageMock, propertyName(Eq(defaultPropertyId)))
|
ON_CALL(projectStorageMock, propertyName(Eq(defaultPropertyId)))
|
||||||
.WillByDefault(Return(defaultPeopertyName));
|
.WillByDefault(Return(defaultPeopertyName));
|
||||||
}
|
}
|
||||||
|
@@ -253,17 +253,15 @@ MATCHER(StringsAreSorted, std::string(negation ? "isn't sorted" : "is sorted"))
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
MATCHER_P3(IsInfoType,
|
MATCHER_P2(IsInfoType,
|
||||||
defaultPropertyId,
|
|
||||||
sourceId,
|
sourceId,
|
||||||
traits,
|
traits,
|
||||||
std::string(negation ? "isn't " : "is ")
|
std::string(negation ? "isn't " : "is ")
|
||||||
+ PrintToString(Storage::Info::Type{defaultPropertyId, sourceId, traits}))
|
+ PrintToString(Storage::Info::Type{sourceId, traits}))
|
||||||
{
|
{
|
||||||
const Storage::Info::Type &type = arg;
|
const Storage::Info::Type &type = arg;
|
||||||
|
|
||||||
return type.defaultPropertyId == defaultPropertyId && type.sourceId == sourceId
|
return type.sourceId == sourceId && type.traits == traits;
|
||||||
&& type.traits == traits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ProjectStorage : public testing::Test
|
class ProjectStorage : public testing::Test
|
||||||
@@ -6683,12 +6681,10 @@ TEST_F(ProjectStorage, get_type)
|
|||||||
auto package{createSimpleSynchronizationPackage()};
|
auto package{createSimpleSynchronizationPackage()};
|
||||||
storage.synchronize(package);
|
storage.synchronize(package);
|
||||||
auto typeId = fetchTypeId(sourceId1, "QQuickItem");
|
auto typeId = fetchTypeId(sourceId1, "QQuickItem");
|
||||||
auto defaultPropertyName = storage.fetchTypeByTypeId(typeId).defaultPropertyName;
|
|
||||||
auto defaultPropertyId = storage.propertyDeclarationId(typeId, defaultPropertyName);
|
|
||||||
|
|
||||||
auto type = storage.type(typeId);
|
auto type = storage.type(typeId);
|
||||||
|
|
||||||
ASSERT_THAT(type, Optional(IsInfoType(defaultPropertyId, sourceId1, TypeTraitsKind::Reference)));
|
ASSERT_THAT(type, Optional(IsInfoType(sourceId1, TypeTraitsKind::Reference)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(ProjectStorage, dont_get_type_for_invalid_id)
|
TEST_F(ProjectStorage, dont_get_type_for_invalid_id)
|
||||||
@@ -6701,6 +6697,58 @@ TEST_F(ProjectStorage, dont_get_type_for_invalid_id)
|
|||||||
ASSERT_THAT(type, Eq(std::nullopt));
|
ASSERT_THAT(type, Eq(std::nullopt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorage, get_default_property_declarartion_id)
|
||||||
|
{
|
||||||
|
auto package{createSimpleSynchronizationPackage()};
|
||||||
|
storage.synchronize(package);
|
||||||
|
auto typeId = fetchTypeId(sourceId1, "QQuickItem");
|
||||||
|
auto defaultPropertyName = storage.fetchTypeByTypeId(typeId).defaultPropertyName;
|
||||||
|
auto defaultPropertyId = storage.propertyDeclarationId(typeId, defaultPropertyName);
|
||||||
|
|
||||||
|
auto propertyId = storage.defaultPropertyDeclarationId(typeId);
|
||||||
|
|
||||||
|
ASSERT_THAT(propertyId, defaultPropertyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorage, get_default_property_declarartion_id_in_base_type)
|
||||||
|
{
|
||||||
|
auto package{createSynchronizationPackageWithAliases()};
|
||||||
|
storage.synchronize(package);
|
||||||
|
auto baseTypeId = fetchTypeId(sourceId1, "QQuickItem");
|
||||||
|
auto defaultPropertyName = storage.fetchTypeByTypeId(baseTypeId).defaultPropertyName;
|
||||||
|
auto defaultPropertyId = storage.propertyDeclarationId(baseTypeId, defaultPropertyName);
|
||||||
|
auto typeId = fetchTypeId(sourceId3, "QAliasItem");
|
||||||
|
|
||||||
|
auto propertyId = storage.defaultPropertyDeclarationId(typeId);
|
||||||
|
|
||||||
|
ASSERT_THAT(propertyId, defaultPropertyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorage, do_not_get_default_property_declarartion_id_wrong_type_in_property_chain)
|
||||||
|
{
|
||||||
|
auto package{createSynchronizationPackageWithAliases()};
|
||||||
|
package.types[1].defaultPropertyName = "objects";
|
||||||
|
storage.synchronize(package);
|
||||||
|
auto baseTypeId = fetchTypeId(sourceId1, "QQuickItem");
|
||||||
|
auto defaultPropertyName = storage.fetchTypeByTypeId(baseTypeId).defaultPropertyName;
|
||||||
|
auto defaultPropertyId = storage.propertyDeclarationId(baseTypeId, defaultPropertyName);
|
||||||
|
auto typeId = fetchTypeId(sourceId3, "QAliasItem");
|
||||||
|
|
||||||
|
auto propertyId = storage.defaultPropertyDeclarationId(typeId);
|
||||||
|
|
||||||
|
ASSERT_THAT(propertyId, defaultPropertyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(ProjectStorage, get_invalid_default_property_declarartion_id_for_invalid_type)
|
||||||
|
{
|
||||||
|
auto package{createSimpleSynchronizationPackage()};
|
||||||
|
storage.synchronize(package);
|
||||||
|
|
||||||
|
auto propertyId = storage.defaultPropertyDeclarationId(TypeId());
|
||||||
|
|
||||||
|
ASSERT_FALSE(propertyId);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ProjectStorage, get_common_type)
|
TEST_F(ProjectStorage, get_common_type)
|
||||||
{
|
{
|
||||||
auto package{createSimpleSynchronizationPackage()};
|
auto package{createSimpleSynchronizationPackage()};
|
||||||
|
Reference in New Issue
Block a user