diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp index e0aac2defbf..2e2e50de49f 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.cpp @@ -3165,21 +3165,25 @@ void ProjectStorage::relinkAliasPropertyDeclarations(AliasPropertyDeclarations & auto typeId = fetchTypeId(alias.aliasImportedTypeNameId); if (typeId) { - auto [propertyImportedTypeNameId, propertyTypeId, aliasId, propertyTraits] - = fetchPropertyDeclarationByTypeIdAndNameUngarded(typeId, alias.aliasPropertyName); + auto propertyDeclaration = fetchPropertyDeclarationByTypeIdAndNameUngarded( + typeId, alias.aliasPropertyName); + if (propertyDeclaration) { + auto [propertyImportedTypeNameId, propertyTypeId, aliasId, propertyTraits] = *propertyDeclaration; - s->updatePropertyDeclarationWithAliasAndTypeStatement.write(alias.propertyDeclarationId, - propertyTypeId, - propertyTraits, - propertyImportedTypeNameId, - aliasId); - } else { - errorNotifier->typeNameCannotBeResolved(fetchImportedTypeName( - alias.aliasImportedTypeNameId), - fetchTypeSourceId(alias.typeId)); - s->resetAliasPropertyDeclarationStatement.write(alias.propertyDeclarationId, - Storage::PropertyDeclarationTraits{}); + s->updatePropertyDeclarationWithAliasAndTypeStatement + .write(alias.propertyDeclarationId, + propertyTypeId, + propertyTraits, + propertyImportedTypeNameId, + aliasId); + return; + } } + + errorNotifier->typeNameCannotBeResolved(fetchImportedTypeName(alias.aliasImportedTypeNameId), + fetchTypeSourceId(alias.typeId)); + s->resetAliasPropertyDeclarationStatement.write(alias.propertyDeclarationId, + Storage::PropertyDeclarationTraits{}); }, TypeCompare{}); } @@ -3321,7 +3325,10 @@ PropertyDeclarationId ProjectStorage::fetchAliasId(TypeId aliasTypeId, auto stemAlias = fetchPropertyDeclarationByTypeIdAndNameUngarded(aliasTypeId, aliasPropertyName); - return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias.propertyTypeId, + if (!stemAlias) + return PropertyDeclarationId{}; + + return fetchPropertyDeclarationIdByTypeIdAndNameUngarded(stemAlias->propertyTypeId, aliasPropertyNameTail); } @@ -3341,10 +3348,22 @@ void ProjectStorage::linkAliasPropertyDeclarationAliasIds( aliasDeclaration.aliasPropertyName, aliasDeclaration.aliasPropertyNameTail); - s->updatePropertyDeclarationAliasIdAndTypeNameIdStatement - .write(aliasDeclaration.propertyDeclarationId, - aliasId, - aliasDeclaration.aliasImportedTypeNameId); + if (aliasId) { + s->updatePropertyDeclarationAliasIdAndTypeNameIdStatement + .write(aliasDeclaration.propertyDeclarationId, + aliasId, + aliasDeclaration.aliasImportedTypeNameId); + } else { + s->resetAliasPropertyDeclarationStatement.write(aliasDeclaration.propertyDeclarationId, + Storage::PropertyDeclarationTraits{}); + s->updatePropertyAliasDeclarationRecursivelyWithTypeAndTraitsStatement + .write(aliasDeclaration.propertyDeclarationId, + TypeId{}, + Storage::PropertyDeclarationTraits{}); + + errorNotifier->propertyNameDoesNotExists(aliasDeclaration.composedProperyName(), + aliasDeclaration.sourceId); + } } else if (raiseError == RaiseError::Yes) { errorNotifier->typeNameCannotBeResolved(fetchImportedTypeName( aliasDeclaration.aliasImportedTypeNameId), @@ -4516,10 +4535,18 @@ void ProjectStorage::syncDefaultProperties(Storage::Synchronization::Types &type keyValue("view", view)}; PropertyDeclarationId valueDefaultPropertyId; - if (value.defaultPropertyName.size()) - valueDefaultPropertyId = fetchPropertyDeclarationByTypeIdAndNameUngarded(value.typeId, - value.defaultPropertyName) - .propertyDeclarationId; + if (value.defaultPropertyName.size()) { + auto defaultPropertyDeclaration = fetchPropertyDeclarationByTypeIdAndNameUngarded( + value.typeId, value.defaultPropertyName); + + if (defaultPropertyDeclaration) { + valueDefaultPropertyId = defaultPropertyDeclaration->propertyDeclarationId; + } else { + errorNotifier->missingDefaultProperty(value.typeName, + value.defaultPropertyName, + value.sourceId); + } + } if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) return Sqlite::UpdateChange::No; @@ -4563,10 +4590,8 @@ void ProjectStorage::resetDefaultPropertiesIfChanged(Storage::Synchronization::T PropertyDeclarationId valueDefaultPropertyId; if (value.defaultPropertyName.size()) { - auto optionalValueDefaultPropertyId = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded( + valueDefaultPropertyId = fetchPropertyDeclarationIdByTypeIdAndNameUngarded( value.typeId, value.defaultPropertyName); - if (optionalValueDefaultPropertyId) - valueDefaultPropertyId = optionalValueDefaultPropertyId->propertyDeclarationId; } if (compareInvalidAreTrue(valueDefaultPropertyId, view.defaultPropertyId)) @@ -4814,8 +4839,8 @@ TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId, } std::optional -ProjectStorage::fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(TypeId typeId, - Utils::SmallStringView name) +ProjectStorage::fetchPropertyDeclarationByTypeIdAndNameUngarded(TypeId typeId, + Utils::SmallStringView name) { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch optional property declaration by type id and name ungarded"_t, @@ -4833,24 +4858,6 @@ ProjectStorage::fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(TypeId t return propertyDeclaration; } -ProjectStorage::FetchPropertyDeclarationResult ProjectStorage::fetchPropertyDeclarationByTypeIdAndNameUngarded( - TypeId typeId, Utils::SmallStringView name) -{ - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch property declaration by type id and name ungarded"_t, - projectStorageCategory(), - keyValue("type id", typeId), - keyValue("property name", name)}; - - auto propertyDeclaration = fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded(typeId, name); - tracer.end(keyValue("property declaration", propertyDeclaration)); - - if (propertyDeclaration) - return *propertyDeclaration; - - throw PropertyNameDoesNotExists{}; -} - PropertyDeclarationId ProjectStorage::fetchPropertyDeclarationIdByTypeIdAndNameUngarded( TypeId typeId, Utils::SmallStringView name) { @@ -4864,10 +4871,7 @@ PropertyDeclarationId ProjectStorage::fetchPropertyDeclarationIdByTypeIdAndNameU tracer.end(keyValue("property declaration id", propertyDeclarationId)); - if (propertyDeclarationId) - return propertyDeclarationId; - - throw PropertyNameDoesNotExists{}; + return propertyDeclarationId; } SourceContextId ProjectStorage::readSourceContextId(Utils::SmallStringView sourceContextPath) diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h index c4ea3acef95..42755ce916e 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h @@ -411,6 +411,14 @@ private: convertToString(string, dict); } + Utils::PathString composedProperyName() const + { + if (aliasPropertyNameTail.empty()) + return aliasPropertyName; + + return Utils::PathString::join({aliasPropertyName, ".", aliasPropertyNameTail}); + } + public: TypeId typeId; PropertyDeclarationId propertyDeclarationId; @@ -991,10 +999,7 @@ private: Storage::PropertyDeclarationTraits propertyTraits; }; - std::optional fetchOptionalPropertyDeclarationByTypeIdAndNameUngarded( - TypeId typeId, Utils::SmallStringView name); - - FetchPropertyDeclarationResult fetchPropertyDeclarationByTypeIdAndNameUngarded( + std::optional fetchPropertyDeclarationByTypeIdAndNameUngarded( TypeId typeId, Utils::SmallStringView name); PropertyDeclarationId fetchPropertyDeclarationIdByTypeIdAndNameUngarded(TypeId typeId, diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp index a4705f5eecb..e8be5dbfbd0 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.cpp @@ -14,4 +14,20 @@ void ProjectStorageErrorNotifier::typeNameCannotBeResolved(Utils::SmallStringVie << " in file: " << m_pathCache.sourcePath(sourceId).toStringView(); } +void ProjectStorageErrorNotifier::missingDefaultProperty(Utils::SmallStringView typeName, + Utils::SmallStringView propertyName, + SourceId sourceId) + +{ + qDebug() << "Missing default property: " << propertyName << " in type: " << typeName + << " in file: " << m_pathCache.sourcePath(sourceId).toStringView(); +} + +void ProjectStorageErrorNotifier::propertyNameDoesNotExists(Utils::SmallStringView propertyName, + SourceId sourceId) +{ + qDebug() << "Missing property: " << propertyName + << " in file: " << m_pathCache.sourcePath(sourceId).toStringView(); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h index 2695e930193..ab1bdd51366 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifier.h @@ -16,7 +16,11 @@ public: : m_pathCache{pathCache} {} - void typeNameCannotBeResolved(Utils::SmallStringView typeName, SourceId souceId) override; + void typeNameCannotBeResolved(Utils::SmallStringView typeName, SourceId sourceId) override; + void missingDefaultProperty(Utils::SmallStringView typeName, + Utils::SmallStringView propertyName, + SourceId sourceId) override; + void propertyNameDoesNotExists(Utils::SmallStringView propertyName, SourceId sourceId) override; private: PathCacheType &m_pathCache; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h index 8136c9d599c..5d370519037 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageerrornotifierinterface.h @@ -18,7 +18,12 @@ public: ProjectStorageErrorNotifierInterface(const ProjectStorageErrorNotifierInterface &) = delete; ProjectStorageErrorNotifierInterface &operator=(const ProjectStorageErrorNotifierInterface &) = delete; - virtual void typeNameCannotBeResolved(Utils::SmallStringView typeName, SourceId souceId) = 0; + virtual void typeNameCannotBeResolved(Utils::SmallStringView typeName, SourceId sourceId) = 0; + virtual void missingDefaultProperty(Utils::SmallStringView typeName, + Utils::SmallStringView propertyName, + SourceId sourceId) + = 0; + virtual void propertyNameDoesNotExists(Utils::SmallStringView propertyName, SourceId sourceId) = 0; protected: ~ProjectStorageErrorNotifierInterface() = default; diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp index a86b78a785f..91e1ce1593b 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp @@ -98,16 +98,6 @@ TypeNameDoesNotExists::TypeNameDoesNotExists(std::string_view typeName, SourceId keyValue("source id", sourceId)); } -PropertyNameDoesNotExists::PropertyNameDoesNotExists() -{ - category().threadEvent("PropertyNameDoesNotExists"_t); -} - -const char *PropertyNameDoesNotExists::what() const noexcept -{ - return "The property name does not exist!"; -} - PrototypeChainCycle::PrototypeChainCycle() { category().threadEvent("PrototypeChainCycle"_t); diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h index f4f78f714bb..0d42d8cce6d 100644 --- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h +++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h @@ -95,13 +95,6 @@ public: TypeNameDoesNotExists(std::string_view typeName, SourceId sourceId = SourceId{}); }; -class QMLDESIGNERCORE_EXPORT PropertyNameDoesNotExists : public ProjectStorageError -{ -public: - PropertyNameDoesNotExists(); - const char *what() const noexcept override; -}; - class QMLDESIGNERCORE_EXPORT PrototypeChainCycle : public ProjectStorageError { public: diff --git a/tests/unit/tests/mocks/projectstorageerrornotifiermock.h b/tests/unit/tests/mocks/projectstorageerrornotifiermock.h index 730c70a66ab..1142342f582 100644 --- a/tests/unit/tests/mocks/projectstorageerrornotifiermock.h +++ b/tests/unit/tests/mocks/projectstorageerrornotifiermock.h @@ -12,6 +12,16 @@ class ProjectStorageErrorNotifierMock : public QmlDesigner::ProjectStorageErrorN public: MOCK_METHOD(void, typeNameCannotBeResolved, - (Utils::SmallStringView typeName, QmlDesigner::SourceId souceId), + (Utils::SmallStringView typeName, QmlDesigner::SourceId sourceId), + (override)); + MOCK_METHOD(void, + missingDefaultProperty, + (Utils::SmallStringView typeName, + Utils::SmallStringView propertyName, + QmlDesigner::SourceId sourceId), + (override)); + MOCK_METHOD(void, + propertyNameDoesNotExists, + (Utils::SmallStringView propertyName, QmlDesigner::SourceId sourceId), (override)); }; diff --git a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp index 1b0a62baa10..45a1f23514b 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp @@ -216,6 +216,11 @@ auto IsNullTypeId() return Property(&QmlDesigner::TypeId::isNull, true); } +auto IsNullPropertyDeclarationId() +{ + return Property(&QmlDesigner::PropertyDeclarationId::isNull, true); +} + template auto HasPrototypeId(const Matcher &matcher) { @@ -1182,6 +1187,19 @@ protected: return storage.fetchTypeByTypeId(storage.fetchTypeIdByName(sourceId, name)); } + auto defaultPropertyDeclarationId(SourceId sourceId, Utils::SmallStringView typeName) + { + return storage.defaultPropertyDeclarationId(storage.fetchTypeIdByName(sourceId, typeName)); + } + + auto propertyDeclarationId(SourceId sourceId, + Utils::SmallStringView typeName, + Utils::SmallStringView propertyName) + { + return storage.propertyDeclarationId(storage.fetchTypeIdByName(sourceId, typeName), + propertyName); + } + static auto &findType(Storage::Synchronization::SynchronizationPackage &package, Utils::SmallStringView name) { @@ -3508,17 +3526,46 @@ TEST_F(ProjectStorage, synchronize_types_fixes_null_type_id_after_add_alias_decl Contains(IsPropertyDeclaration("items", fetchTypeId(sourceId1, "QQuickItem"))))); } -TEST_F(ProjectStorage, synchronize_types_add_alias_declarations_throws_for_wrong_property_name) +TEST_F(ProjectStorage, synchronize_types_add_alias_declarations_notifies_error_for_wrong_property_name) { auto package{createSynchronizationPackageWithAliases()}; package.types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; - ASSERT_THROW(storage.synchronize(SynchronizationPackage{package.imports, - package.types, - {sourceId4}, - package.moduleDependencies, - {sourceId4}}), - QmlDesigner::PropertyNameDoesNotExists); + EXPECT_CALL(errorNotifierMock, propertyNameDoesNotExists(Eq("childrenWrong"), sourceId3)) + .Times(AtLeast(1)); + + storage.synchronize( + {package.imports, package.types, {sourceId4}, package.moduleDependencies, {sourceId4}}); +} + +TEST_F(ProjectStorage, + synchronize_types_add_alias_declarations_returns_invalid_type_for_wrong_property_name) +{ + auto package{createSynchronizationPackageWithAliases()}; + package.types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; + + storage.synchronize( + {package.imports, package.types, {sourceId4}, package.moduleDependencies, {sourceId4}}); + + ASSERT_THAT(fetchType(sourceId3, "QAliasItem"), + PropertyDeclarations(Contains(IsPropertyDeclaration("items", IsNullTypeId())))); +} + +TEST_F(ProjectStorage, + synchronize_types_update_alias_declarations_returns_item_type_for_fixed_property_name) +{ + auto package{createSynchronizationPackageWithAliases()}; + package.types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; + storage.synchronize( + {package.imports, package.types, {sourceId4}, package.moduleDependencies, {sourceId4}}); + package.types[2].propertyDeclarations[1].aliasPropertyName = "children"; + + storage.synchronize( + {importsSourceId3 + moduleDependenciesSourceId3, {package.types[2]}, {sourceId3}}); + + ASSERT_THAT(fetchType(sourceId3, "QAliasItem"), + PropertyDeclarations( + Contains(IsPropertyDeclaration("items", fetchTypeId(sourceId1, "QQuickItem"))))); } TEST_F(ProjectStorage, synchronize_types_change_alias_declarations_type_name) @@ -6540,33 +6587,94 @@ TEST_F(ProjectStorage, PropertyDeclarations(Not(Contains(IsPropertyDeclaration("objects", IsNullTypeId()))))); } -TEST_F(ProjectStorage, synchronize_types_add_indirect_alias_declarations_throws_for_wrong_property_name) +TEST_F(ProjectStorage, + synchronize_types_add_indirect_alias_declarations_notifies_error_for_wrong_property_name) { auto package{createSynchronizationPackageWithIndirectAliases()}; storage.synchronize(package); package.types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; - ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId3, - {package.types[2]}, - {sourceId3}, - moduleDependenciesSourceId3, - {sourceId3}}), - QmlDesigner::PropertyNameDoesNotExists); + EXPECT_CALL(errorNotifierMock, propertyNameDoesNotExists(Eq("childrenWrong.objects"), sourceId3)); + + storage.synchronize( + {importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}}); } TEST_F(ProjectStorage, - synchronize_types_add_indirect_alias_declarations_throws_for_wrong_property_name_tail) + synchronize_types_add_indirect_alias_declarations_returns_null_type_id_for_wrong_property_name) +{ + auto package{createSynchronizationPackageWithIndirectAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; + + storage.synchronize( + {importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}}); + + ASSERT_THAT(fetchType(sourceId3, "QAliasItem"), + PropertyDeclarations(Contains(IsPropertyDeclaration("objects", IsNullTypeId())))); +} + +TEST_F(ProjectStorage, + synchronize_types_updated_indirect_alias_declarations_returns_item_type_id_for_wrong_property_name) +{ + auto package{createSynchronizationPackageWithIndirectAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations[1].aliasPropertyName = "childrenWrong"; + storage.synchronize( + {importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}}); + package.types[2].propertyDeclarations[1].aliasPropertyName = "children"; + + storage.synchronize( + {importsSourceId3 + moduleDependenciesSourceId3, {package.types[2]}, {sourceId3}}); + + ASSERT_THAT(fetchType(sourceId3, "QAliasItem"), + PropertyDeclarations( + Contains(IsPropertyDeclaration("objects", fetchTypeId(sourceId2, "QObject"))))); +} + +TEST_F(ProjectStorage, + synchronize_types_add_indirect_alias_declarations_notifies_error_for_wrong_property_name_tail) { auto package{createSynchronizationPackageWithIndirectAliases()}; storage.synchronize(package); package.types[2].propertyDeclarations[1].aliasPropertyNameTail = "objectsWrong"; - ASSERT_THROW(storage.synchronize(SynchronizationPackage{importsSourceId3, - {package.types[2]}, - {sourceId3}, - moduleDependenciesSourceId3, - {sourceId3}}), - QmlDesigner::PropertyNameDoesNotExists); + EXPECT_CALL(errorNotifierMock, propertyNameDoesNotExists(Eq("children.objectsWrong"), sourceId3)); + + storage.synchronize(SynchronizationPackage{ + importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}}); +} + +TEST_F(ProjectStorage, + synchronize_types_add_indirect_alias_declarations_sets_property_declaration_id_to_null_for_the_wrong_property_name_tail) +{ + auto package{createSynchronizationPackageWithIndirectAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations[1].aliasPropertyNameTail = "objectsWrong"; + + storage.synchronize(SynchronizationPackage{ + importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}}); + + ASSERT_THAT(fetchType(sourceId3, "QAliasItem"), + PropertyDeclarations(Contains(IsPropertyDeclaration("objects", IsNullTypeId())))); +} + +TEST_F(ProjectStorage, + synchronize_types_updates_indirect_alias_declarations_fixed_property_declaration_id_for_property_name_tail) +{ + auto package{createSynchronizationPackageWithIndirectAliases()}; + storage.synchronize(package); + package.types[2].propertyDeclarations[1].aliasPropertyNameTail = "objectsWrong"; + storage.synchronize( + {importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}}); + package.types[2].propertyDeclarations[1].aliasPropertyNameTail = "objects"; + + storage.synchronize( + {importsSourceId3 + moduleDependenciesSourceId3, {package.types[2]}, {sourceId3}}); + + ASSERT_THAT(fetchType(sourceId3, "QAliasItem"), + PropertyDeclarations(Contains( + IsPropertyDeclaration("objects", Eq(fetchTypeId(sourceId2, "QObject")))))); } TEST_F(ProjectStorage, synchronize_types_change_indirect_alias_declaration_type_name) @@ -7407,23 +7515,64 @@ TEST_F(ProjectStorage, synchronize_to_removed_default_property) Contains(AllOf(HasTypeName(Eq("QQuickItem")), HasDefaultPropertyName(IsEmpty())))); } -TEST_F(ProjectStorage, synchronize_default_property_throws_for_missing_default_property) +TEST_F(ProjectStorage, synchronize_default_property_notifies_error_for_missing_default_property) { auto package{createSimpleSynchronizationPackage()}; package.types.front().defaultPropertyName = "child"; - ASSERT_THROW(storage.synchronize(package), QmlDesigner::PropertyNameDoesNotExists); + EXPECT_CALL(errorNotifierMock, missingDefaultProperty(Eq("QQuickItem"), Eq("child"), sourceId1)); + + storage.synchronize(package); +} + +TEST_F(ProjectStorage, gets_null_default_property_id_for_broken_default_property_name) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types.front().defaultPropertyName = "child"; + + storage.synchronize(package); + + ASSERT_THAT(defaultPropertyDeclarationId(sourceId1, "QQuickItem"), IsNullPropertyDeclarationId()); +} + +TEST_F(ProjectStorage, synchronize_default_fixes_default_property_name) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types.front().defaultPropertyName = "child"; + storage.synchronize(package); + package.types.front().defaultPropertyName = "data"; + + storage.synchronize(package); + + ASSERT_THAT(defaultPropertyDeclarationId(sourceId1, "QQuickItem"), + Eq(propertyDeclarationId(sourceId1, "QQuickItem", "data"))); } TEST_F(ProjectStorage, - synchronize_default_property_throws_for_removing_property_without_changing_default_property) + synchronize_default_property_notifies_error_for_removing_property_without_changing_default_property) { auto package{createSimpleSynchronizationPackage()}; package.types.front().defaultPropertyName = "children"; storage.synchronize(package); removeProperty(package, "QQuickItem", "children"); - ASSERT_THROW(storage.synchronize(package), QmlDesigner::PropertyNameDoesNotExists); + EXPECT_CALL(errorNotifierMock, + missingDefaultProperty(Eq("QQuickItem"), Eq("children"), sourceId1)); + + storage.synchronize(package); +} + +TEST_F(ProjectStorage, + synchronize_default_property_has_null_id_for_removing_property_without_changing_default_property) +{ + auto package{createSimpleSynchronizationPackage()}; + package.types.front().defaultPropertyName = "children"; + storage.synchronize(package); + removeProperty(package, "QQuickItem", "children"); + + storage.synchronize(package); + + ASSERT_THAT(defaultPropertyDeclarationId(sourceId1, "QQuickItem"), IsNullPropertyDeclarationId()); } TEST_F(ProjectStorage, synchronize_changes_default_property_and_removes_old_default_property)