forked from qt-creator/qt-creator
QmlDesigner: Use error notifier for prototype and extension type name resolving
If the prototype or extension has an unresolved id, it needs to be checked, if an exported name belonging to the prototype or extension was updated. In that case the id has to be again resolved. Task-number: QDS-12761 Change-Id: I7a733662cf37e13e8c2db53dec5a4f3e0a9b6ecf Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -36,13 +36,6 @@ class DatabaseBackend;
|
||||
|
||||
enum class Type : char { Invalid, Integer, Float, Text, Blob, Null };
|
||||
|
||||
template<typename Enumeration>
|
||||
constexpr static std::underlying_type_t<Enumeration> to_underlying(Enumeration enumeration) noexcept
|
||||
{
|
||||
static_assert(std::is_enum_v<Enumeration>, "to_underlying expect an enumeration");
|
||||
return static_cast<std::underlying_type_t<Enumeration>>(enumeration);
|
||||
}
|
||||
|
||||
class SQLITE_EXPORT BaseStatement
|
||||
{
|
||||
public:
|
||||
@@ -87,7 +80,7 @@ public:
|
||||
template<typename Type, typename = std::enable_if_t<Type::IsBasicId::value>>
|
||||
void bind(int index, Type id)
|
||||
{
|
||||
if (id)
|
||||
if (!id.isNull())
|
||||
bind(index, id.internalId());
|
||||
else
|
||||
bindNull(index);
|
||||
|
@@ -11,6 +11,13 @@
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
template<typename Enumeration>
|
||||
static constexpr std::underlying_type_t<Enumeration> to_underlying(Enumeration enumeration) noexcept
|
||||
{
|
||||
static_assert(std::is_enum_v<Enumeration>, "to_underlying expect an enumeration");
|
||||
return static_cast<std::underlying_type_t<Enumeration>>(enumeration);
|
||||
}
|
||||
|
||||
template<auto Type, typename InternalIntegerType = long long>
|
||||
class BasicId
|
||||
{
|
||||
@@ -27,7 +34,15 @@ public:
|
||||
return id;
|
||||
}
|
||||
|
||||
constexpr friend bool compareInvalidAreTrue(BasicId first, BasicId second)
|
||||
template<typename Enumeration>
|
||||
static constexpr BasicId createSpecialState(Enumeration specialState)
|
||||
{
|
||||
BasicId id;
|
||||
id.id = ::Sqlite::to_underlying(specialState);
|
||||
return id;
|
||||
}
|
||||
|
||||
friend constexpr bool compareInvalidAreTrue(BasicId first, BasicId second)
|
||||
{
|
||||
return first.id == second.id;
|
||||
}
|
||||
@@ -57,6 +72,14 @@ public:
|
||||
|
||||
constexpr bool isValid() const { return id > 0; }
|
||||
|
||||
constexpr bool isNull() const { return id == 0; }
|
||||
|
||||
template<typename Enumeration>
|
||||
constexpr bool hasSpecialState(Enumeration specialState) const
|
||||
{
|
||||
return id == ::Sqlite::to_underlying(specialState);
|
||||
}
|
||||
|
||||
explicit operator bool() const { return isValid(); }
|
||||
|
||||
explicit operator std::size_t() const { return static_cast<std::size_t>(id); }
|
||||
@@ -68,13 +91,13 @@ public:
|
||||
template<typename String>
|
||||
friend void convertToString(String &string, BasicId id)
|
||||
{
|
||||
if (id.isValid())
|
||||
NanotraceHR::convertToString(string, id.internalId());
|
||||
if (id.isNull())
|
||||
NanotraceHR::convertToString(string, "invalid null");
|
||||
else
|
||||
NanotraceHR::convertToString(string, "invalid");
|
||||
NanotraceHR::convertToString(string, id.internalId());
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
InternalIntegerType id = 0;
|
||||
};
|
||||
|
||||
|
@@ -7,6 +7,25 @@
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
enum class SpecialIdState { Unresolved = -1 };
|
||||
|
||||
constexpr TypeId unresolvedTypeId = TypeId::createSpecialState(SpecialIdState::Unresolved);
|
||||
|
||||
class UnresolvedTypeId : public TypeId
|
||||
{
|
||||
public:
|
||||
constexpr UnresolvedTypeId()
|
||||
: TypeId{TypeId::createSpecialState(SpecialIdState::Unresolved)}
|
||||
{}
|
||||
|
||||
static constexpr UnresolvedTypeId create(DatabaseType idNumber)
|
||||
{
|
||||
UnresolvedTypeId id;
|
||||
id.id = idNumber;
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
struct ProjectStorage::Statements
|
||||
{
|
||||
Statements(Sqlite::Database &database)
|
||||
@@ -17,9 +36,13 @@ struct ProjectStorage::Statements
|
||||
Sqlite::ReadWriteStatement<1, 2> insertTypeStatement{
|
||||
"INSERT OR IGNORE INTO types(sourceId, name) VALUES(?1, ?2) RETURNING typeId", database};
|
||||
Sqlite::WriteStatement<5> updatePrototypeAndExtensionStatement{
|
||||
"UPDATE types SET prototypeId=?2, prototypeNameId=?3, extensionId=?4, extensionNameId=?5 "
|
||||
"WHERE typeId=?1 AND (prototypeId IS NOT ?2 OR extensionId IS NOT ?3 AND prototypeId "
|
||||
"IS NOT ?4 OR extensionNameId IS NOT ?5)",
|
||||
"UPDATE types "
|
||||
"SET prototypeId=?2, prototypeNameId=?3, extensionId=?4, extensionNameId=?5 "
|
||||
"WHERE typeId=?1 AND ( "
|
||||
" prototypeId IS NOT ?2 "
|
||||
" OR extensionId IS NOT ?3 "
|
||||
" OR prototypeId IS NOT ?4 "
|
||||
" OR extensionNameId IS NOT ?5)",
|
||||
database};
|
||||
mutable Sqlite::ReadStatement<1, 1> selectTypeIdByExportedNameStatement{
|
||||
"SELECT typeId FROM exportedTypeNames WHERE name=?1", database};
|
||||
@@ -357,13 +380,51 @@ struct ProjectStorage::Statements
|
||||
"SELECT name FROM propertyDeclarations WHERE propertyDeclarationId=?", database};
|
||||
Sqlite::WriteStatement<2> updatePropertyDeclarationTypeStatement{
|
||||
"UPDATE propertyDeclarations SET propertyTypeId=?2 WHERE propertyDeclarationId=?1", database};
|
||||
Sqlite::ReadWriteStatement<2, 1> updatePrototypeIdToNullStatement{
|
||||
"UPDATE types SET prototypeId=NULL WHERE prototypeId=?1 RETURNING "
|
||||
"typeId, prototypeNameId",
|
||||
Sqlite::ReadWriteStatement<2, 2> updatePrototypeIdToTypeIdStatement{
|
||||
"UPDATE types "
|
||||
"SET prototypeId=?2 "
|
||||
"WHERE prototypeId=?1 "
|
||||
"RETURNING typeId, prototypeNameId",
|
||||
database};
|
||||
Sqlite::ReadWriteStatement<2, 1> updateExtensionIdToNullStatement{
|
||||
"UPDATE types SET extensionId=NULL WHERE extensionId=?1 RETURNING "
|
||||
"typeId, extensionNameId",
|
||||
Sqlite::ReadWriteStatement<2, 2> updateExtensionIdToTypeIdStatement{
|
||||
"UPDATE types "
|
||||
"SET extensionId=?2 "
|
||||
"WHERE extensionId=?1 "
|
||||
"RETURNING typeId, extensionNameId",
|
||||
database};
|
||||
Sqlite::ReadStatement<2, 2> selectTypeIdAndPrototypeNameIdForPrototypeIdAndTypeNameStatement{
|
||||
"SELECT typeId, prototypeNameId "
|
||||
"FROM types "
|
||||
"WHERE prototypeNameId IN ( "
|
||||
" SELECT importedTypeNameId "
|
||||
" FROM "
|
||||
" importedTypeNames WHERE name=?1) "
|
||||
" AND prototypeId=?2",
|
||||
database};
|
||||
Sqlite::ReadStatement<2, 2> selectTypeIdAndPrototypeNameIdForPrototypeIdAndSourceIdStatement{
|
||||
"SELECT typeId , prototypeNameId "
|
||||
"FROM types "
|
||||
"WHERE prototypeId=?1 AND sourceId=?2",
|
||||
database};
|
||||
Sqlite::ReadStatement<2, 2> selectTypeIdAndExtensionNameIdForExtensionIdAndSourceIdStatement{
|
||||
"SELECT typeId, extensionNameId "
|
||||
"FROM types "
|
||||
"WHERE extensionId=?1 AND sourceId=?2",
|
||||
database};
|
||||
Sqlite::ReadWriteStatement<3, 3> updatePrototypeIdAndExtensionIdToTypeIdForSourceIdStatement{
|
||||
"UPDATE types "
|
||||
"SET prototypeId=?2, extensionId=?3 "
|
||||
"WHERE sourceId=?1 "
|
||||
"RETURNING typeId, prototypeNameId, extensionNameId",
|
||||
database};
|
||||
Sqlite::ReadStatement<2, 2> selectTypeIdForExtensionIdAndTypeNameStatement{
|
||||
"SELECT typeId , prototypeNameId "
|
||||
"FROM types "
|
||||
"WHERE extensionNameId IN ( "
|
||||
" SELECT importedTypeNameId "
|
||||
" FROM importedTypeNames "
|
||||
" WHERE name=?1) "
|
||||
" AND extensionId=?2",
|
||||
database};
|
||||
Sqlite::WriteStatement<2> updateTypePrototypeStatement{
|
||||
"UPDATE types SET prototypeId=?2 WHERE typeId=?1", database};
|
||||
@@ -619,6 +680,8 @@ struct ProjectStorage::Statements
|
||||
"UPDATE types SET defaultPropertyId=NULL WHERE defaultPropertyId=?1", database};
|
||||
mutable Sqlite::ReadStatement<3, 1> selectInfoTypeByTypeIdStatement{
|
||||
"SELECT sourceId, traits, annotationTraits FROM types WHERE typeId=?", database};
|
||||
mutable Sqlite::ReadStatement<1, 1> selectSourceIdByTypeIdStatement{
|
||||
"SELECT sourceId FROM types WHERE typeId=?", database};
|
||||
mutable Sqlite::ReadStatement<1, 1> selectPrototypeAnnotationTraitsByTypeIdStatement{
|
||||
"SELECT annotationTraits "
|
||||
"FROM types "
|
||||
@@ -801,23 +864,23 @@ public:
|
||||
auto &sourceIdColumn = typesTable.addColumn("sourceId", Sqlite::StrictColumnType::Integer);
|
||||
auto &typesNameColumn = typesTable.addColumn("name", Sqlite::StrictColumnType::Text);
|
||||
typesTable.addColumn("traits", Sqlite::StrictColumnType::Integer);
|
||||
auto &prototypeIdColumn = typesTable.addForeignKeyColumn("prototypeId",
|
||||
typesTable,
|
||||
Sqlite::ForeignKeyAction::NoAction,
|
||||
Sqlite::ForeignKeyAction::Restrict);
|
||||
typesTable.addColumn("prototypeNameId", Sqlite::StrictColumnType::Integer);
|
||||
auto &extensionIdColumn = typesTable.addForeignKeyColumn("extensionId",
|
||||
typesTable,
|
||||
Sqlite::ForeignKeyAction::NoAction,
|
||||
Sqlite::ForeignKeyAction::Restrict);
|
||||
typesTable.addColumn("extensionNameId", Sqlite::StrictColumnType::Integer);
|
||||
auto &prototypeIdColumn = typesTable.addColumn("prototypeId",
|
||||
Sqlite::StrictColumnType::Integer);
|
||||
auto &prototypeNameIdColumn = typesTable.addColumn("prototypeNameId",
|
||||
Sqlite::StrictColumnType::Integer);
|
||||
auto &extensionIdColumn = typesTable.addColumn("extensionId",
|
||||
Sqlite::StrictColumnType::Integer);
|
||||
auto &extensionNameIdColumn = typesTable.addColumn("extensionNameId",
|
||||
Sqlite::StrictColumnType::Integer);
|
||||
auto &defaultPropertyIdColumn = typesTable.addColumn("defaultPropertyId",
|
||||
Sqlite::StrictColumnType::Integer);
|
||||
typesTable.addColumn("annotationTraits", Sqlite::StrictColumnType::Integer);
|
||||
typesTable.addUniqueIndex({sourceIdColumn, typesNameColumn});
|
||||
typesTable.addIndex({defaultPropertyIdColumn});
|
||||
typesTable.addIndex({prototypeIdColumn});
|
||||
typesTable.addIndex({extensionIdColumn});
|
||||
typesTable.addIndex({prototypeIdColumn, sourceIdColumn});
|
||||
typesTable.addIndex({extensionIdColumn, sourceIdColumn});
|
||||
typesTable.addIndex({prototypeNameIdColumn});
|
||||
typesTable.addIndex({extensionNameIdColumn});
|
||||
|
||||
typesTable.initialize(database);
|
||||
|
||||
@@ -1131,7 +1194,7 @@ ProjectStorage::ProjectStorage(Database &database,
|
||||
ProjectStorageErrorNotifierInterface &errorNotifier,
|
||||
bool isInitialized)
|
||||
: database{database}
|
||||
, errorNotifier{errorNotifier}
|
||||
, errorNotifier{&errorNotifier}
|
||||
, exclusiveTransaction{database}
|
||||
, initializer{std::make_unique<ProjectStorage::Initializer>(database, isInitialized)}
|
||||
, moduleCache{ModuleStorageAdapter{*this}}
|
||||
@@ -1175,7 +1238,9 @@ void ProjectStorage::synchronize(Storage::Synchronization::SynchronizationPackag
|
||||
package.moduleDependencies,
|
||||
package.updatedModuleDependencySourceIds,
|
||||
package.moduleExportedImports,
|
||||
package.updatedModuleIds);
|
||||
package.updatedModuleIds,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions);
|
||||
synchronizeTypes(package.types,
|
||||
updatedTypeIds,
|
||||
insertedAliasPropertyDeclarations,
|
||||
@@ -1223,7 +1288,24 @@ void ProjectStorage::synchronizeDocumentImports(Storage::Imports imports, Source
|
||||
keyValue("source id", sourceId)};
|
||||
|
||||
Sqlite::withImmediateTransaction(database, [&] {
|
||||
synchronizeDocumentImports(imports, {sourceId}, Storage::Synchronization::ImportKind::Import);
|
||||
AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
|
||||
PropertyDeclarations relinkablePropertyDeclarations;
|
||||
Prototypes relinkablePrototypes;
|
||||
Prototypes relinkableExtensions;
|
||||
TypeIds deletedTypeIds;
|
||||
|
||||
synchronizeDocumentImports(imports,
|
||||
{sourceId},
|
||||
Storage::Synchronization::ImportKind::Import,
|
||||
Relink::Yes,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions);
|
||||
|
||||
relink(relinkableAliasPropertyDeclarations,
|
||||
relinkablePropertyDeclarations,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions,
|
||||
deletedTypeIds);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2642,19 +2724,29 @@ void ProjectStorage::synchronizeImports(Storage::Imports &imports,
|
||||
Storage::Imports &moduleDependencies,
|
||||
const SourceIds &updatedModuleDependencySourceIds,
|
||||
Storage::Synchronization::ModuleExportedImports &moduleExportedImports,
|
||||
const ModuleIds &updatedModuleIds)
|
||||
const ModuleIds &updatedModuleIds,
|
||||
Prototypes &relinkablePrototypes,
|
||||
Prototypes &relinkableExtensions)
|
||||
{
|
||||
NanotraceHR::Tracer tracer{"synchronize imports"_t, projectStorageCategory()};
|
||||
|
||||
synchromizeModuleExportedImports(moduleExportedImports, updatedModuleIds);
|
||||
NanotraceHR::Tracer importTracer{"synchronize qml document imports"_t, projectStorageCategory()};
|
||||
synchronizeDocumentImports(imports, updatedSourceIds, Storage::Synchronization::ImportKind::Import);
|
||||
synchronizeDocumentImports(imports,
|
||||
updatedSourceIds,
|
||||
Storage::Synchronization::ImportKind::Import,
|
||||
Relink::No,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions);
|
||||
importTracer.end();
|
||||
NanotraceHR::Tracer moduleDependenciesTracer{"synchronize module depdencies"_t,
|
||||
projectStorageCategory()};
|
||||
synchronizeDocumentImports(moduleDependencies,
|
||||
updatedModuleDependencySourceIds,
|
||||
Storage::Synchronization::ImportKind::ModuleDependency);
|
||||
Storage::Synchronization::ImportKind::ModuleDependency,
|
||||
Relink::Yes,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions);
|
||||
moduleDependenciesTracer.end();
|
||||
}
|
||||
|
||||
@@ -2821,11 +2913,30 @@ void ProjectStorage::handlePrototypes(TypeId prototypeId, Prototypes &relinkable
|
||||
keyValue("type id", prototypeId),
|
||||
keyValue("relinkable prototypes", relinkablePrototypes)};
|
||||
|
||||
auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) {
|
||||
if (prototypeNameId)
|
||||
relinkablePrototypes.emplace_back(typeId, prototypeNameId);
|
||||
};
|
||||
|
||||
s->updatePrototypeIdToTypeIdStatement.readCallback(callback, prototypeId, unresolvedTypeId);
|
||||
}
|
||||
|
||||
void ProjectStorage::handlePrototypesWithExportedTypeNameAndTypeId(
|
||||
Utils::SmallStringView exportedTypeName, TypeId typeId, Prototypes &relinkablePrototypes)
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"handle invalid prototypes"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("type id", exportedTypeName),
|
||||
keyValue("relinkable prototypes", relinkablePrototypes)};
|
||||
|
||||
auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) {
|
||||
relinkablePrototypes.emplace_back(typeId, prototypeNameId);
|
||||
};
|
||||
|
||||
s->updatePrototypeIdToNullStatement.readCallback(callback, prototypeId);
|
||||
s->selectTypeIdAndPrototypeNameIdForPrototypeIdAndTypeNameStatement.readCallback(callback,
|
||||
exportedTypeName,
|
||||
typeId);
|
||||
}
|
||||
|
||||
void ProjectStorage::handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions)
|
||||
@@ -2836,11 +2947,28 @@ void ProjectStorage::handleExtensions(TypeId extensionId, Prototypes &relinkable
|
||||
keyValue("type id", extensionId),
|
||||
keyValue("relinkable extensions", relinkableExtensions)};
|
||||
|
||||
auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) {
|
||||
if (extensionNameId)
|
||||
relinkableExtensions.emplace_back(typeId, extensionNameId);
|
||||
};
|
||||
|
||||
s->updateExtensionIdToTypeIdStatement.readCallback(callback, extensionId, unresolvedTypeId);
|
||||
}
|
||||
|
||||
void ProjectStorage::handleExtensionsWithExportedTypeNameAndTypeId(
|
||||
Utils::SmallStringView exportedTypeName, TypeId typeId, Prototypes &relinkableExtensions)
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"handle invalid extensions"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("type id", exportedTypeName),
|
||||
keyValue("relinkable extensions", relinkableExtensions)};
|
||||
|
||||
auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) {
|
||||
relinkableExtensions.emplace_back(typeId, extensionNameId);
|
||||
};
|
||||
|
||||
s->updateExtensionIdToNullStatement.readCallback(callback, extensionId);
|
||||
s->selectTypeIdForExtensionIdAndTypeNameStatement.readCallback(callback, exportedTypeName, typeId);
|
||||
}
|
||||
|
||||
void ProjectStorage::deleteType(TypeId typeId,
|
||||
@@ -2927,6 +3055,39 @@ void ProjectStorage::relinkPropertyDeclarations(PropertyDeclarations &relinkable
|
||||
TypeCompare<PropertyDeclaration>{});
|
||||
}
|
||||
|
||||
template<typename Callable>
|
||||
void ProjectStorage::relinkPrototypes(Prototypes &relinkablePrototypes,
|
||||
const TypeIds &deletedTypeIds,
|
||||
Callable updateStatement)
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"relink prototypes"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("relinkable prototypes", relinkablePrototypes),
|
||||
keyValue("deleted type ids", deletedTypeIds)};
|
||||
|
||||
std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end());
|
||||
relinkablePrototypes.erase(std::unique(relinkablePrototypes.begin(), relinkablePrototypes.end()),
|
||||
relinkablePrototypes.end());
|
||||
|
||||
Utils::set_greedy_difference(
|
||||
relinkablePrototypes.cbegin(),
|
||||
relinkablePrototypes.cend(),
|
||||
deletedTypeIds.begin(),
|
||||
deletedTypeIds.end(),
|
||||
[&](const Prototype &prototype) {
|
||||
TypeId prototypeId = fetchTypeId(prototype.prototypeNameId);
|
||||
|
||||
if (!prototypeId)
|
||||
errorNotifier->typeNameCannotBeResolved(fetchImportedTypeName(prototype.prototypeNameId),
|
||||
fetchTypeSourceId(prototype.typeId));
|
||||
|
||||
updateStatement(prototype.typeId, prototypeId);
|
||||
checkForPrototypeChainCycle(prototype.typeId);
|
||||
},
|
||||
TypeCompare<Prototype>{});
|
||||
}
|
||||
|
||||
void ProjectStorage::deleteNotUpdatedTypes(const TypeIds &updatedTypeIds,
|
||||
const SourceIds &updatedSourceIds,
|
||||
const TypeIds &typeIdsToBeDeleted,
|
||||
@@ -3141,6 +3302,9 @@ void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds,
|
||||
} catch (const Sqlite::ConstraintPreventsModification &) {
|
||||
throw QmlDesigner::ExportedTypeCannotBeInserted{type.name};
|
||||
}
|
||||
|
||||
handlePrototypesWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkablePrototypes);
|
||||
handleExtensionsWithExportedTypeNameAndTypeId(type.name, unresolvedTypeId, relinkableExtensions);
|
||||
};
|
||||
|
||||
auto update = [&](const Storage::Synchronization::ExportedTypeView &view,
|
||||
@@ -3176,6 +3340,7 @@ void ProjectStorage::synchronizeExportedTypes(const TypeIds &updatedTypeIds,
|
||||
relinkableAliasPropertyDeclarations);
|
||||
handlePrototypes(view.typeId, relinkablePrototypes);
|
||||
handleExtensions(view.typeId, relinkableExtensions);
|
||||
|
||||
s->deleteExportedTypeNameStatement.write(view.exportedTypeNameId);
|
||||
};
|
||||
|
||||
@@ -3491,11 +3656,90 @@ void ProjectStorage::resetRemovedAliasPropertyDeclarationsToNull(
|
||||
PropertyCompare<AliasPropertyDeclaration>{});
|
||||
}
|
||||
|
||||
void ProjectStorage::handlePrototypesWithSourceIdAndPrototypeId(SourceId sourceId,
|
||||
TypeId prototypeId,
|
||||
Prototypes &relinkablePrototypes)
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"handle prototypes with source id and prototype id"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("source id", sourceId),
|
||||
keyValue("type id", prototypeId)};
|
||||
|
||||
auto callback = [&](TypeId typeId, ImportedTypeNameId prototypeNameId) {
|
||||
if (prototypeNameId)
|
||||
relinkablePrototypes.emplace_back(typeId, prototypeNameId);
|
||||
};
|
||||
|
||||
s->selectTypeIdAndPrototypeNameIdForPrototypeIdAndSourceIdStatement.readCallback(callback,
|
||||
prototypeId,
|
||||
sourceId);
|
||||
}
|
||||
|
||||
void ProjectStorage::handlePrototypesAndExtensionsWithSourceId(SourceId sourceId,
|
||||
TypeId prototypeId,
|
||||
TypeId extensionId,
|
||||
Prototypes &relinkablePrototypes,
|
||||
Prototypes &relinkableExtensions)
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"handle prototypes with source id"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("source id", sourceId),
|
||||
keyValue("prototype id", prototypeId),
|
||||
keyValue("extension id", extensionId)};
|
||||
|
||||
auto callback =
|
||||
[&](TypeId typeId, ImportedTypeNameId prototypeNameId, ImportedTypeNameId extensionNameId) {
|
||||
if (prototypeNameId)
|
||||
relinkablePrototypes.emplace_back(typeId, prototypeNameId);
|
||||
if (extensionNameId)
|
||||
relinkableExtensions.emplace_back(typeId, extensionNameId);
|
||||
};
|
||||
|
||||
s->updatePrototypeIdAndExtensionIdToTypeIdForSourceIdStatement.readCallback(callback,
|
||||
sourceId,
|
||||
prototypeId,
|
||||
extensionId);
|
||||
}
|
||||
|
||||
void ProjectStorage::handleExtensionsWithSourceIdAndExtensionId(SourceId sourceId,
|
||||
TypeId extensionId,
|
||||
Prototypes &relinkableExtensions)
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"handle prototypes with source id and prototype id"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("source id", sourceId),
|
||||
keyValue("type id", extensionId)};
|
||||
|
||||
auto callback = [&](TypeId typeId, ImportedTypeNameId extensionNameId) {
|
||||
if (extensionNameId)
|
||||
relinkableExtensions.emplace_back(typeId, extensionNameId);
|
||||
};
|
||||
|
||||
s->selectTypeIdAndExtensionNameIdForExtensionIdAndSourceIdStatement.readCallback(callback,
|
||||
extensionId,
|
||||
sourceId);
|
||||
}
|
||||
|
||||
ImportId ProjectStorage::insertDocumentImport(const Storage::Import &import,
|
||||
Storage::Synchronization::ImportKind importKind,
|
||||
ModuleId sourceModuleId,
|
||||
ImportId parentImportId)
|
||||
ImportId parentImportId,
|
||||
Relink relink,
|
||||
Prototypes &relinkablePrototypes,
|
||||
Prototypes &relinkableExtensions)
|
||||
{
|
||||
if (relink == Relink::Yes) {
|
||||
handlePrototypesWithSourceIdAndPrototypeId(import.sourceId,
|
||||
unresolvedTypeId,
|
||||
relinkablePrototypes);
|
||||
handleExtensionsWithSourceIdAndExtensionId(import.sourceId,
|
||||
unresolvedTypeId,
|
||||
relinkableExtensions);
|
||||
}
|
||||
|
||||
if (import.version.minor) {
|
||||
return s->insertDocumentImportWithVersionStatement.value<ImportId>(import.sourceId,
|
||||
import.moduleId,
|
||||
@@ -3522,7 +3766,10 @@ ImportId ProjectStorage::insertDocumentImport(const Storage::Import &import,
|
||||
|
||||
void ProjectStorage::synchronizeDocumentImports(Storage::Imports &imports,
|
||||
const SourceIds &updatedSourceIds,
|
||||
Storage::Synchronization::ImportKind importKind)
|
||||
Storage::Synchronization::ImportKind importKind,
|
||||
Relink relink,
|
||||
Prototypes &relinkablePrototypes,
|
||||
Prototypes &relinkableExtensions)
|
||||
{
|
||||
std::sort(imports.begin(), imports.end(), [](auto &&first, auto &&second) {
|
||||
return std::tie(first.sourceId, first.moduleId, first.version)
|
||||
@@ -3559,7 +3806,13 @@ void ProjectStorage::synchronizeDocumentImports(Storage::Imports &imports,
|
||||
keyValue("source id", import.sourceId),
|
||||
keyValue("module id", import.moduleId)};
|
||||
|
||||
auto importId = insertDocumentImport(import, importKind, import.moduleId, ImportId{});
|
||||
auto importId = insertDocumentImport(import,
|
||||
importKind,
|
||||
import.moduleId,
|
||||
ImportId{},
|
||||
relink,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions);
|
||||
auto callback = [&](ModuleId exportedModuleId, int majorVersion, int minorVersion) {
|
||||
Storage::Import additionImport{exportedModuleId,
|
||||
Storage::Version{majorVersion, minorVersion},
|
||||
@@ -3579,7 +3832,10 @@ void ProjectStorage::synchronizeDocumentImports(Storage::Imports &imports,
|
||||
auto indirectImportId = insertDocumentImport(additionImport,
|
||||
exportedImportKind,
|
||||
import.moduleId,
|
||||
importId);
|
||||
importId,
|
||||
relink,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions);
|
||||
|
||||
tracer.end(keyValue("import id", indirectImportId));
|
||||
};
|
||||
@@ -3606,6 +3862,13 @@ void ProjectStorage::synchronizeDocumentImports(Storage::Imports &imports,
|
||||
|
||||
s->deleteDocumentImportStatement.write(view.importId);
|
||||
s->deleteDocumentImportsWithParentImportIdStatement.write(view.sourceId, view.importId);
|
||||
if (relink == Relink::Yes) {
|
||||
handlePrototypesAndExtensionsWithSourceId(view.sourceId,
|
||||
unresolvedTypeId,
|
||||
unresolvedTypeId,
|
||||
relinkablePrototypes,
|
||||
relinkableExtensions);
|
||||
}
|
||||
};
|
||||
|
||||
Sqlite::insertUpdateDelete(range, imports, compareKey, insert, update, remove);
|
||||
@@ -4156,25 +4419,29 @@ void ProjectStorage::checkForAliasChainCycle(PropertyDeclarationId propertyDecla
|
||||
}
|
||||
|
||||
std::pair<TypeId, ImportedTypeNameId> ProjectStorage::fetchImportedTypeNameIdAndTypeId(
|
||||
const Storage::Synchronization::ImportedTypeName &typeName, SourceId sourceId)
|
||||
const Storage::Synchronization::ImportedTypeName &importedTypeName, SourceId sourceId)
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"fetch imported type name id and type id"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("imported type name", typeName),
|
||||
keyValue("imported type name", importedTypeName),
|
||||
keyValue("source id", sourceId)};
|
||||
|
||||
TypeId typeId;
|
||||
ImportedTypeNameId typeNameId;
|
||||
if (!std::visit([](auto &&typeName_) -> bool { return typeName_.name.isEmpty(); }, typeName)) {
|
||||
typeNameId = fetchImportedTypeNameId(typeName, sourceId);
|
||||
auto typeName = std::visit([](auto &&importedTypeName) { return importedTypeName.name; },
|
||||
importedTypeName);
|
||||
if (!typeName.empty()) {
|
||||
typeNameId = fetchImportedTypeNameId(importedTypeName, sourceId);
|
||||
|
||||
typeId = fetchTypeId(typeNameId);
|
||||
|
||||
tracer.end(keyValue("type id", typeId), keyValue("type name id", typeNameId));
|
||||
|
||||
if (!typeId)
|
||||
throw TypeNameDoesNotExists{fetchImportedTypeName(typeNameId), sourceId};
|
||||
if (!typeId) {
|
||||
errorNotifier->typeNameCannotBeResolved(typeName, sourceId);
|
||||
return {unresolvedTypeId, typeNameId};
|
||||
}
|
||||
}
|
||||
|
||||
return {typeId, typeNameId};
|
||||
@@ -4323,6 +4590,11 @@ Utils::SmallString ProjectStorage::fetchImportedTypeName(ImportedTypeNameId type
|
||||
return s->selectNameFromImportedTypeNamesStatement.value<Utils::SmallString>(typeNameId);
|
||||
}
|
||||
|
||||
SourceId ProjectStorage::fetchTypeSourceId(TypeId typeId) const
|
||||
{
|
||||
return s->selectSourceIdByTypeIdStatement.value<SourceId>(typeId);
|
||||
}
|
||||
|
||||
TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId,
|
||||
Storage::Synchronization::TypeNameKind kind) const
|
||||
{
|
||||
@@ -4334,9 +4606,10 @@ TypeId ProjectStorage::fetchTypeId(ImportedTypeNameId typeNameId,
|
||||
|
||||
TypeId typeId;
|
||||
if (kind == Storage::Synchronization::TypeNameKind::Exported) {
|
||||
typeId = s->selectTypeIdForImportedTypeNameNamesStatement.value<TypeId>(typeNameId);
|
||||
typeId = s->selectTypeIdForImportedTypeNameNamesStatement.value<UnresolvedTypeId>(typeNameId);
|
||||
} else {
|
||||
typeId = s->selectTypeIdForQualifiedImportedTypeNameNamesStatement.value<TypeId>(typeNameId);
|
||||
typeId = s->selectTypeIdForQualifiedImportedTypeNameNamesStatement.value<UnresolvedTypeId>(
|
||||
typeNameId);
|
||||
}
|
||||
|
||||
tracer.end(keyValue("type id", typeId));
|
||||
|
@@ -39,6 +39,8 @@ class ProjectStorage final : public ProjectStorageInterface
|
||||
using Database = Sqlite::Database;
|
||||
friend Storage::Info::CommonTypeCache<ProjectStorageType>;
|
||||
|
||||
enum class Relink { No, Yes };
|
||||
|
||||
public:
|
||||
ProjectStorage(Database &database,
|
||||
ProjectStorageErrorNotifierInterface &errorNotifier,
|
||||
@@ -49,6 +51,11 @@ public:
|
||||
|
||||
void synchronizeDocumentImports(Storage::Imports imports, SourceId sourceId) override;
|
||||
|
||||
void setErrorNotifier(ProjectStorageErrorNotifierInterface &errorNotifier)
|
||||
{
|
||||
this->errorNotifier = &errorNotifier;
|
||||
}
|
||||
|
||||
void addObserver(ProjectStorageObserver *observer) override;
|
||||
|
||||
void removeObserver(ProjectStorageObserver *observer) override;
|
||||
@@ -443,6 +450,11 @@ private:
|
||||
return first.typeId < second.typeId;
|
||||
}
|
||||
|
||||
friend bool operator==(Prototype first, Prototype second)
|
||||
{
|
||||
return first.typeId == second.typeId;
|
||||
}
|
||||
|
||||
template<typename String>
|
||||
friend void convertToString(String &string, const Prototype &prototype)
|
||||
{
|
||||
@@ -575,7 +587,9 @@ private:
|
||||
Storage::Imports &moduleDependencies,
|
||||
const SourceIds &updatedModuleDependencySourceIds,
|
||||
Storage::Synchronization::ModuleExportedImports &moduleExportedImports,
|
||||
const ModuleIds &updatedModuleIds);
|
||||
const ModuleIds &updatedModuleIds,
|
||||
Prototypes &relinkablePrototypes,
|
||||
Prototypes &relinkableExtensions);
|
||||
|
||||
void synchromizeModuleExportedImports(
|
||||
Storage::Synchronization::ModuleExportedImports &moduleExportedImports,
|
||||
@@ -593,9 +607,14 @@ private:
|
||||
PropertyDeclarations &relinkablePropertyDeclarations);
|
||||
|
||||
void handlePrototypes(TypeId prototypeId, Prototypes &relinkablePrototypes);
|
||||
void handlePrototypesWithExportedTypeNameAndTypeId(Utils::SmallStringView exportedTypeName,
|
||||
TypeId typeId,
|
||||
Prototypes &relinkablePrototypes);
|
||||
|
||||
void handleExtensions(TypeId extensionId, Prototypes &relinkableExtensions);
|
||||
|
||||
void handleExtensionsWithExportedTypeNameAndTypeId(Utils::SmallStringView exportedTypeName,
|
||||
TypeId typeId,
|
||||
Prototypes &relinkableExtensions);
|
||||
void deleteType(TypeId typeId,
|
||||
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations,
|
||||
PropertyDeclarations &relinkablePropertyDeclarations,
|
||||
@@ -611,32 +630,7 @@ private:
|
||||
template<typename Callable>
|
||||
void relinkPrototypes(Prototypes &relinkablePrototypes,
|
||||
const TypeIds &deletedTypeIds,
|
||||
Callable updateStatement)
|
||||
{
|
||||
using NanotraceHR::keyValue;
|
||||
NanotraceHR::Tracer tracer{"relink prototypes"_t,
|
||||
projectStorageCategory(),
|
||||
keyValue("relinkable prototypes", relinkablePrototypes),
|
||||
keyValue("deleted type ids", deletedTypeIds)};
|
||||
|
||||
std::sort(relinkablePrototypes.begin(), relinkablePrototypes.end());
|
||||
|
||||
Utils::set_greedy_difference(
|
||||
relinkablePrototypes.cbegin(),
|
||||
relinkablePrototypes.cend(),
|
||||
deletedTypeIds.begin(),
|
||||
deletedTypeIds.end(),
|
||||
[&](const Prototype &prototype) {
|
||||
TypeId prototypeId = fetchTypeId(prototype.prototypeNameId);
|
||||
|
||||
if (!prototypeId)
|
||||
throw TypeNameDoesNotExists{fetchImportedTypeName(prototype.prototypeNameId)};
|
||||
|
||||
updateStatement(prototype.typeId, prototypeId);
|
||||
checkForPrototypeChainCycle(prototype.typeId);
|
||||
},
|
||||
TypeCompare<Prototype>{});
|
||||
}
|
||||
Callable updateStatement);
|
||||
|
||||
void deleteNotUpdatedTypes(const TypeIds &updatedTypeIds,
|
||||
const SourceIds &updatedSourceIds,
|
||||
@@ -751,14 +745,32 @@ private:
|
||||
Storage::Synchronization::Types &types,
|
||||
AliasPropertyDeclarations &relinkableAliasPropertyDeclarations);
|
||||
|
||||
void handlePrototypesWithSourceIdAndPrototypeId(SourceId sourceId,
|
||||
TypeId prototypeId,
|
||||
Prototypes &relinkablePrototypes);
|
||||
void handlePrototypesAndExtensionsWithSourceId(SourceId sourceId,
|
||||
TypeId prototypeId,
|
||||
TypeId extensionId,
|
||||
Prototypes &relinkablePrototypes,
|
||||
Prototypes &relinkableExtensions);
|
||||
void handleExtensionsWithSourceIdAndExtensionId(SourceId sourceId,
|
||||
TypeId extensionId,
|
||||
Prototypes &relinkableExtensions);
|
||||
|
||||
ImportId insertDocumentImport(const Storage::Import &import,
|
||||
Storage::Synchronization::ImportKind importKind,
|
||||
ModuleId sourceModuleId,
|
||||
ImportId parentImportId);
|
||||
ImportId parentImportId,
|
||||
Relink forceRelink,
|
||||
Prototypes &relinkablePrototypes,
|
||||
Prototypes &relinkableExtensions);
|
||||
|
||||
void synchronizeDocumentImports(Storage::Imports &imports,
|
||||
const SourceIds &updatedSourceIds,
|
||||
Storage::Synchronization::ImportKind importKind);
|
||||
Storage::Synchronization::ImportKind importKind,
|
||||
Relink forceRelink,
|
||||
Prototypes &relinkablePrototypes,
|
||||
Prototypes &relinkableExtensions);
|
||||
|
||||
static Utils::PathString createJson(const Storage::Synchronization::ParameterDeclarations ¶meters);
|
||||
|
||||
@@ -904,6 +916,7 @@ private:
|
||||
TypeId fetchTypeId(ImportedTypeNameId typeNameId) const;
|
||||
|
||||
Utils::SmallString fetchImportedTypeName(ImportedTypeNameId typeNameId) const;
|
||||
SourceId fetchTypeSourceId(TypeId typeId) const;
|
||||
|
||||
TypeId fetchTypeId(ImportedTypeNameId typeNameId,
|
||||
Storage::Synchronization::TypeNameKind kind) const;
|
||||
@@ -970,7 +983,7 @@ private:
|
||||
|
||||
public:
|
||||
Database &database;
|
||||
ProjectStorageErrorNotifierInterface &errorNotifier;
|
||||
ProjectStorageErrorNotifierInterface *errorNotifier = nullptr; // cannot be null
|
||||
Sqlite::ExclusiveNonThrowingDestructorTransaction<Database> exclusiveTransaction;
|
||||
std::unique_ptr<Initializer> initializer;
|
||||
mutable ModuleCache moduleCache{ModuleStorageAdapter{*this}};
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
class ProjectStorageErrorNotifierMock : public QmlDesigner::ProjectStorageErrorNotifierInterface
|
||||
{
|
||||
public:
|
||||
MOCK_METHOD(void,
|
||||
typeNameCannotBeResolved,
|
||||
(Utils::SmallStringView typeName, QmlDesigner::SourceId souceId),
|
||||
|
@@ -833,8 +833,9 @@ std::ostream &operator<<(std::ostream &out, const Type &type)
|
||||
{
|
||||
using std::operator<<;
|
||||
using Utils::operator<<;
|
||||
return out << "( typename: \"" << type.typeName << "\", prototype: " << type.prototype << ", "
|
||||
<< type.prototypeId << ", " << type.traits << ", source: " << type.sourceId
|
||||
return out << "( typename: \"" << type.typeName << "\", prototype: {\"" << type.prototype
|
||||
<< "\", " << type.prototypeId << "}, " << "\", extension: {\"" << type.extension
|
||||
<< "\", " << type.extensionId << "}, " << type.traits << ", source: " << type.sourceId
|
||||
<< ", exports: " << type.exportedTypes << ", properties: " << type.propertyDeclarations
|
||||
<< ", functions: " << type.functionDeclarations
|
||||
<< ", signals: " << type.signalDeclarations << ", changeLevel: " << type.changeLevel
|
||||
|
@@ -205,6 +205,23 @@ MATCHER_P4(IsInfoPropertyDeclaration,
|
||||
&& propertyDeclaration.traits == traits;
|
||||
}
|
||||
|
||||
auto IsUnresolvedTypeId()
|
||||
{
|
||||
return Property(&QmlDesigner::TypeId::internalId, -1);
|
||||
}
|
||||
|
||||
template<typename Matcher>
|
||||
auto IsPrototypeId(const Matcher &matcher)
|
||||
{
|
||||
return Field(&Storage::Synchronization::Type::prototypeId, matcher);
|
||||
}
|
||||
|
||||
template<typename Matcher>
|
||||
auto IsExtensionId(const Matcher &matcher)
|
||||
{
|
||||
return Field(&Storage::Synchronization::Type::extensionId, matcher);
|
||||
}
|
||||
|
||||
class HasNameMatcher
|
||||
{
|
||||
public:
|
||||
@@ -286,6 +303,8 @@ protected:
|
||||
|
||||
static void TearDownTestSuite() { staticData.reset(); }
|
||||
|
||||
ProjectStorage() { storage.setErrorNotifier(errorNotifierMock); }
|
||||
|
||||
~ProjectStorage() { storage.resetForTestsOnly(); }
|
||||
|
||||
template<typename Range>
|
||||
@@ -312,6 +331,32 @@ protected:
|
||||
storage.fetchSourceId(sourceContextId3, "bar");
|
||||
}
|
||||
|
||||
auto createVerySimpleSynchronizationPackage()
|
||||
{
|
||||
SynchronizationPackage package;
|
||||
|
||||
package.types.push_back(Storage::Synchronization::Type{
|
||||
"QQuickItem",
|
||||
Storage::Synchronization::ImportedType{},
|
||||
Storage::Synchronization::ImportedType{},
|
||||
TypeTraitsKind::Reference,
|
||||
sourceId1,
|
||||
{Storage::Synchronization::ExportedType{qtQuickModuleId, "Item"},
|
||||
Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}});
|
||||
package.types.push_back(Storage::Synchronization::Type{
|
||||
"QObject",
|
||||
Storage::Synchronization::ImportedType{},
|
||||
Storage::Synchronization::ImportedType{},
|
||||
TypeTraitsKind::Reference,
|
||||
sourceId2,
|
||||
{Storage::Synchronization::ExportedType{qmlModuleId, "Object"},
|
||||
Storage::Synchronization::ExportedType{qmlNativeModuleId, "QObject"}}});
|
||||
|
||||
package.updatedSourceIds = {sourceId1, sourceId2};
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
auto createSimpleSynchronizationPackage()
|
||||
{
|
||||
SynchronizationPackage package;
|
||||
@@ -1142,7 +1187,7 @@ protected:
|
||||
inline static std::unique_ptr<StaticData> staticData;
|
||||
Sqlite::Database &database = staticData->database;
|
||||
QmlDesigner::ProjectStorage &storage = staticData->storage;
|
||||
ProjectStorageErrorNotifierMock &errorNotifierMock = staticData->errorNotifierMock;
|
||||
NiceMock<ProjectStorageErrorNotifierMock> errorNotifierMock;
|
||||
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage> sourcePathCache{storage};
|
||||
QmlDesigner::SourcePathView path1{"/path1/to"};
|
||||
QmlDesigner::SourcePathView path2{"/path2/to"};
|
||||
@@ -1486,22 +1531,193 @@ TEST_F(ProjectStorage, synchronize_types_adds_new_types_with_exported_extension_
|
||||
"QQuickItem"))))));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_adds_new_types_throws_with_wrong_prototype_name)
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_adds_unknown_prototype_which_notifies_about_unresolved_type_name)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Objec"};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(std::move(package)), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Objec"), sourceId1));
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_adds_new_types_throws_with_wrong_extension_name)
|
||||
TEST_F(ProjectStorage, synchronize_types_adds_unknown_prototype_as_unresolved_type_id)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Objec"};
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsPrototypeId(IsUnresolvedTypeId()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_updates_unresolved_prototype_after_exported_type_name_is_added)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Objec"};
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsPrototypeId(fetchTypeId(sourceId2, "QObject")));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_updates_prototype_to_unresolved_after_exported_type_name_is_removed)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Objec"};
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.pop_back();
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsPrototypeId(IsUnresolvedTypeId()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_updates_unresolved_prototype_indirectly_after_exported_type_name_is_added)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Objec"};
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
package.types.erase(package.types.begin());
|
||||
package.updatedSourceIds = {sourceId2};
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsPrototypeId(fetchTypeId(sourceId2, "QObject")));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_updates_prototype_indirectly_to_unresolved_after_exported_type_name_is_removed)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Objec"};
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.pop_back();
|
||||
package.types.erase(package.types.begin());
|
||||
package.updatedSourceIds = {sourceId2};
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsPrototypeId(IsUnresolvedTypeId()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_updates_prototype_indirectly_to_unresolved_after_exported_type_name_is_removed_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Objec"};
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.pop_back();
|
||||
package.types.erase(package.types.begin());
|
||||
package.updatedSourceIds = {sourceId2};
|
||||
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Objec"), sourceId1));
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_updates_unresolved_extension_after_exported_type_name_is_added)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"Objec"};
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsExtensionId(fetchTypeId(sourceId2, "QObject")));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_updates_extension_to_unresolved_after_exported_type_name_is_removed)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"Objec"};
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.pop_back();
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsExtensionId(IsUnresolvedTypeId()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_updates_unresolved_extension_indirectly_after_exported_type_name_is_added)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"Objec"};
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
package.types.erase(package.types.begin());
|
||||
package.updatedSourceIds = {sourceId2};
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsExtensionId(fetchTypeId(sourceId2, "QObject")));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_updates_invalid_extension_indirectly_after_exported_type_name_is_removed)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"Objec"};
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.pop_back();
|
||||
package.types.erase(package.types.begin());
|
||||
package.updatedSourceIds = {sourceId2};
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsExtensionId(IsUnresolvedTypeId()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_types_updates_extension_indirectly_to_unresolved_after_exported_type_name_is_removed_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"Objec"};
|
||||
package.types[1].exportedTypes.emplace_back(qmlNativeModuleId, "Objec");
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes.pop_back();
|
||||
package.types.erase(package.types.begin());
|
||||
package.updatedSourceIds = {sourceId2};
|
||||
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Objec"), sourceId1));
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_adds_extension_which_notifies_about_unresolved_type_name)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"Objec"};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(std::move(package)), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Objec"), sourceId1));
|
||||
|
||||
storage.synchronize(std::move(package));
|
||||
}
|
||||
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_adds_new_types_with_missing_module)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
@@ -1774,7 +1990,7 @@ TEST_F(ProjectStorage, synchronize_types_add_qualified_extension)
|
||||
IsExportedType(qtQuickNativeModuleId, "QQuickItem"))))));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_throws_for_missing_prototype)
|
||||
TEST_F(ProjectStorage, synchronize_types_notifies_cannot_resolve_for_missing_prototype)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types = {Storage::Synchronization::Type{
|
||||
@@ -1786,10 +2002,12 @@ TEST_F(ProjectStorage, synchronize_types_throws_for_missing_prototype)
|
||||
{Storage::Synchronization::ExportedType{qtQuickModuleId, "Item"},
|
||||
Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("QObject"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_throws_for_missing_extension)
|
||||
TEST_F(ProjectStorage, synchronize_types_notifies_cannot_resolve_for_missing_extension)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types = {Storage::Synchronization::Type{
|
||||
@@ -1801,7 +2019,9 @@ TEST_F(ProjectStorage, synchronize_types_throws_for_missing_extension)
|
||||
{Storage::Synchronization::ExportedType{qtQuickModuleId, "Item"},
|
||||
Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QQuickItem"}}}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("QObject"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_types_throws_for_invalid_module)
|
||||
@@ -3670,7 +3890,8 @@ TEST_F(ProjectStorage, change_extension_type_module_id)
|
||||
TypeTraitsKind::Reference)));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, change_qualified_prototype_type_module_id_throws)
|
||||
TEST_F(ProjectStorage,
|
||||
change_qualified_prototype_type_module_id_notifies_that_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
|
||||
@@ -3678,12 +3899,12 @@ TEST_F(ProjectStorage, change_qualified_prototype_type_module_id_throws)
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes[0].moduleId = qtQuickModuleId;
|
||||
|
||||
ASSERT_THROW(storage.synchronize(
|
||||
SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, change_qualified_extension_type_module_id_throws)
|
||||
TEST_F(ProjectStorage, change_qualified_extension_type_module_id_notifies_cannot_resolve)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
std::swap(package.types.front().extension, package.types.front().prototype);
|
||||
@@ -3692,9 +3913,9 @@ TEST_F(ProjectStorage, change_qualified_extension_type_module_id_throws)
|
||||
storage.synchronize(package);
|
||||
package.types[1].exportedTypes[0].moduleId = qtQuickModuleId;
|
||||
|
||||
ASSERT_THROW(storage.synchronize(
|
||||
SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, change_qualified_prototype_type_module_id)
|
||||
@@ -3798,9 +4019,9 @@ TEST_F(ProjectStorage, change_prototype_type_name_throws_for_wrong_native_protot
|
||||
package.types[1].exportedTypes[2].name = "QObject3";
|
||||
package.types[1].typeName = "QObject3";
|
||||
|
||||
ASSERT_THROW(storage.synchronize(
|
||||
SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("QObject"), sourceId1));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, change_extension_type_name_throws_for_wrong_native_extension_type_name)
|
||||
@@ -3813,9 +4034,9 @@ TEST_F(ProjectStorage, change_extension_type_name_throws_for_wrong_native_extens
|
||||
package.types[1].exportedTypes[2].name = "QObject3";
|
||||
package.types[1].typeName = "QObject3";
|
||||
|
||||
ASSERT_THROW(storage.synchronize(
|
||||
SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("QObject"), sourceId1));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, throw_for_prototype_chain_cycles)
|
||||
@@ -4117,23 +4338,29 @@ TEST_F(ProjectStorage, qualified_extension)
|
||||
TypeTraitsKind::Reference)));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_prototype_upper_down_the_module_chain_throws)
|
||||
TEST_F(ProjectStorage,
|
||||
qualified_prototype_upper_down_the_module_chain_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
|
||||
"Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_extension_upper_down_the_module_chain_throws)
|
||||
TEST_F(ProjectStorage,
|
||||
qualified_extension_upper_down_the_module_chain_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
std::swap(package.types.front().extension, package.types.front().prototype);
|
||||
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
|
||||
"Object", Storage::Import{qtQuickModuleId, Storage::Version{}, sourceId1}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_prototype_upper_in_the_module_chain)
|
||||
@@ -4189,7 +4416,7 @@ TEST_F(ProjectStorage, qualified_extension_upper_in_the_module_chain)
|
||||
TypeTraitsKind::Reference)));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_prototype_with_wrong_version_throws)
|
||||
TEST_F(ProjectStorage, qualified_prototype_with_wrong_version_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
|
||||
@@ -4205,10 +4432,12 @@ TEST_F(ProjectStorage, qualified_prototype_with_wrong_version_throws)
|
||||
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
|
||||
package.updatedSourceIds.push_back(sourceId3);
|
||||
|
||||
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_extension_with_wrong_version_throws)
|
||||
TEST_F(ProjectStorage, qualified_extension_with_wrong_version_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
std::swap(package.types.front().extension, package.types.front().prototype);
|
||||
@@ -4225,7 +4454,9 @@ TEST_F(ProjectStorage, qualified_extension_with_wrong_version_throws)
|
||||
package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
|
||||
package.updatedSourceIds.push_back(sourceId3);
|
||||
|
||||
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_prototype_with_version)
|
||||
@@ -4338,23 +4569,29 @@ TEST_F(ProjectStorage, qualified_extension_with_version_in_the_proto_type_chain)
|
||||
TypeTraitsKind::Reference)));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_prototype_with_version_down_the_proto_type_chain_throws)
|
||||
TEST_F(ProjectStorage,
|
||||
qualified_prototype_with_version_down_the_proto_type_chain_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
|
||||
"Object", Storage::Import{qtQuickModuleId, Storage::Version{2}, sourceId1}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_extension_with_version_down_the_proto_type_chain_throws)
|
||||
TEST_F(ProjectStorage,
|
||||
qualified_extension_with_version_down_the_proto_type_chain_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
std::swap(package.types.front().extension, package.types.front().prototype);
|
||||
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
|
||||
"Object", Storage::Import{qtQuickModuleId, Storage::Version{2}, sourceId1}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, qualified_property_declaration_type_name)
|
||||
@@ -4659,7 +4896,7 @@ TEST_F(ProjectStorage, fetch_by_major_version_and_minor_version_for_qualified_im
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
fetch_by_major_version_and_minor_version_for_imported_type_if_minor_version_is_not_exported_throws)
|
||||
fetch_by_major_version_and_minor_version_for_imported_type_if_minor_version_is_not_exported_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSynchronizationPackageWithVersions()};
|
||||
storage.synchronize(package);
|
||||
@@ -4673,12 +4910,13 @@ TEST_F(ProjectStorage,
|
||||
Storage::Version{}}}};
|
||||
Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId2));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
fetch_by_major_version_and_minor_version_for_qualified_imported_type_if_minor_version_is_not_exported_throws)
|
||||
fetch_by_major_version_and_minor_version_for_qualified_imported_type_if_minor_version_is_not_exported_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSynchronizationPackageWithVersions()};
|
||||
storage.synchronize(package);
|
||||
@@ -4691,11 +4929,12 @@ TEST_F(ProjectStorage,
|
||||
sourceId2,
|
||||
{Storage::Synchronization::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId2));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, fetch_low_minor_version_for_imported_type_throws)
|
||||
TEST_F(ProjectStorage, fetch_low_minor_version_for_imported_type_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSynchronizationPackageWithVersions()};
|
||||
storage.synchronize(package);
|
||||
@@ -4709,11 +4948,13 @@ TEST_F(ProjectStorage, fetch_low_minor_version_for_imported_type_throws)
|
||||
Storage::Version{}}}};
|
||||
Storage::Import import{qmlModuleId, Storage::Version{1, 1}, sourceId2};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Obj"), sourceId2));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, fetch_low_minor_version_for_qualified_imported_type_throws)
|
||||
TEST_F(ProjectStorage,
|
||||
fetch_low_minor_version_for_qualified_imported_type_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSynchronizationPackageWithVersions()};
|
||||
storage.synchronize(package);
|
||||
@@ -4726,8 +4967,9 @@ TEST_F(ProjectStorage, fetch_low_minor_version_for_qualified_imported_type_throw
|
||||
sourceId2,
|
||||
{Storage::Synchronization::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Obj"), sourceId2));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, fetch_higher_minor_version_for_imported_type)
|
||||
@@ -4775,7 +5017,8 @@ TEST_F(ProjectStorage, fetch_higher_minor_version_for_qualified_imported_type)
|
||||
TypeTraitsKind::Reference)));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, fetch_different_major_version_for_imported_type_throws)
|
||||
TEST_F(ProjectStorage,
|
||||
fetch_different_major_version_for_imported_type_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSynchronizationPackageWithVersions()};
|
||||
storage.synchronize(package);
|
||||
@@ -4789,11 +5032,13 @@ TEST_F(ProjectStorage, fetch_different_major_version_for_imported_type_throws)
|
||||
Storage::Version{}}}};
|
||||
Storage::Import import{qmlModuleId, Storage::Version{3, 1}, sourceId2};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Obj"), sourceId2));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, fetch_different_major_version_for_qualified_imported_type_throws)
|
||||
TEST_F(ProjectStorage,
|
||||
fetch_different_major_version_for_qualified_imported_type_notifies_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createSynchronizationPackageWithVersions()};
|
||||
storage.synchronize(package);
|
||||
@@ -4806,8 +5051,9 @@ TEST_F(ProjectStorage, fetch_different_major_version_for_qualified_imported_type
|
||||
sourceId2,
|
||||
{Storage::Synchronization::ExportedType{qtQuickModuleId, "Item", Storage::Version{}}}};
|
||||
|
||||
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
|
||||
QmlDesigner::TypeNameDoesNotExists);
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Obj"), sourceId2));
|
||||
|
||||
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, fetch_other_type_by_different_version_for_imported_type)
|
||||
@@ -7248,6 +7494,46 @@ TEST_F(ProjectStorage, synchronize_document_imports_adds_import)
|
||||
ASSERT_TRUE(storage.importId(imports.back()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
synchronize_document_imports_removes_import_notifies_that_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Object"};
|
||||
storage.synchronize(package);
|
||||
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("Object"), sourceId1));
|
||||
|
||||
storage.synchronizeDocumentImports({}, sourceId1);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_document_imports_removes_import_which_makes_prototype_unresolved)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Object"};
|
||||
storage.synchronize(package);
|
||||
|
||||
storage.synchronizeDocumentImports({}, sourceId1);
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsPrototypeId(IsUnresolvedTypeId()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, synchronize_document_imports_adds_import_which_makes_prototype_resolved)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"Object"};
|
||||
storage.synchronize(package);
|
||||
Storage::Imports imports;
|
||||
imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
|
||||
|
||||
storage.synchronizeDocumentImports(imports, sourceId1);
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsPrototypeId(fetchTypeId(sourceId2, "QObject")));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, get_exported_type_names)
|
||||
{
|
||||
auto package{createSimpleSynchronizationPackage()};
|
||||
@@ -7996,4 +8282,105 @@ TEST_F(ProjectStorage, get_no_hair_ids_for_invalid_type_id)
|
||||
|
||||
ASSERT_THAT(heirIds, IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
removed_document_import_notifies_for_prototypes_that_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1);
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"QObject"};
|
||||
storage.synchronize(package);
|
||||
package.moduleDependencies.clear();
|
||||
package.types.clear();
|
||||
package.updatedSourceIds.clear();
|
||||
package.updatedModuleDependencySourceIds = {sourceId1};
|
||||
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("QObject"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage,
|
||||
removed_document_import_notifies_for_extensions_that_type_name_cannot_be_resolved)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1);
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"QObject"};
|
||||
storage.synchronize(package);
|
||||
package.moduleDependencies.clear();
|
||||
package.types.clear();
|
||||
package.updatedSourceIds.clear();
|
||||
package.updatedModuleDependencySourceIds = {sourceId1};
|
||||
|
||||
EXPECT_CALL(errorNotifierMock, typeNameCannotBeResolved(Eq("QObject"), sourceId1));
|
||||
|
||||
storage.synchronize(package);
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, removed_document_import_changes_prototype_to_unresolved)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1);
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"QObject"};
|
||||
storage.synchronize(package);
|
||||
package.moduleDependencies.clear();
|
||||
package.types.clear();
|
||||
package.updatedSourceIds.clear();
|
||||
package.updatedModuleDependencySourceIds = {sourceId1};
|
||||
|
||||
storage.synchronize(package);
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
Field(&Storage::Synchronization::Type::prototypeId, IsUnresolvedTypeId()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, removed_document_import_changes_extension_to_unresolved)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1);
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"QObject"};
|
||||
storage.synchronize(package);
|
||||
package.moduleDependencies.clear();
|
||||
package.types.clear();
|
||||
package.updatedSourceIds.clear();
|
||||
package.updatedModuleDependencySourceIds = {sourceId1};
|
||||
|
||||
storage.synchronize(package);
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
Field(&Storage::Synchronization::Type::extensionId, IsUnresolvedTypeId()));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, added_document_import_fixes_unresolved_prototype)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.types[0].prototype = Storage::Synchronization::ImportedType{"QObject"};
|
||||
storage.synchronize(package);
|
||||
package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1);
|
||||
package.types.clear();
|
||||
package.updatedSourceIds.clear();
|
||||
package.updatedModuleDependencySourceIds = {sourceId1};
|
||||
|
||||
storage.synchronize(package);
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsPrototypeId(fetchTypeId(sourceId2, "QObject")));
|
||||
}
|
||||
|
||||
TEST_F(ProjectStorage, added_document_import_fixes_unresolved_extension)
|
||||
{
|
||||
auto package{createVerySimpleSynchronizationPackage()};
|
||||
package.types[0].extension = Storage::Synchronization::ImportedType{"QObject"};
|
||||
storage.synchronize(package);
|
||||
package.moduleDependencies.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId1);
|
||||
package.types.clear();
|
||||
package.updatedSourceIds.clear();
|
||||
package.updatedModuleDependencySourceIds = {sourceId1};
|
||||
|
||||
storage.synchronize(package);
|
||||
|
||||
ASSERT_THAT(storage.fetchTypeByTypeId(fetchTypeId(sourceId1, "QQuickItem")),
|
||||
IsExtensionId(fetchTypeId(sourceId2, "QObject")));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@@ -269,6 +269,21 @@ TEST_F(SqliteStatement, bind_int_id)
|
||||
ASSERT_THAT(readStatement.fetchIntValue(0), 42);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, bind_special_state_id)
|
||||
{
|
||||
enum class SpecialIdState { Unresolved = -1 };
|
||||
constexpr TestIntId unresolvedTypeId = TestIntId::createSpecialState(SpecialIdState::Unresolved);
|
||||
SqliteTestStatement<0, 1> statement("INSERT INTO test VALUES ('id', 323, ?)", database);
|
||||
|
||||
statement.bind(1, unresolvedTypeId);
|
||||
statement.next();
|
||||
|
||||
SqliteTestStatement<1, 1> readStatement("SELECT value FROM test WHERE name='id'", database);
|
||||
readStatement.next();
|
||||
ASSERT_THAT(readStatement.fetchType(0), Sqlite::Type::Integer);
|
||||
ASSERT_THAT(readStatement.fetchIntValue(0), -1);
|
||||
}
|
||||
|
||||
TEST_F(SqliteStatement, bind_invalid_long_long_id_to_null)
|
||||
{
|
||||
TestLongLongId id;
|
||||
|
Reference in New Issue
Block a user