QmlDesigner: Add support for implicit import "."

Task-number: QDS-6780
Change-Id: Idd8b58a04203f56296e72dd3bbb73f720eb02277
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Marco Bubke
2022-05-16 17:14:46 +02:00
parent 5f04711011
commit 4eade91d81
2 changed files with 58 additions and 37 deletions

View File

@@ -214,6 +214,8 @@ void ProjectStorageUpdater::updateQmldirs(const QStringList &qmlDirs,
for (const QString &qmldirPath : qmlDirs) { for (const QString &qmldirPath : qmlDirs) {
SourcePath qmldirSourcePath{qmldirPath}; SourcePath qmldirSourcePath{qmldirPath};
SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath); SourceId qmlDirSourceId = m_pathCache.sourceId(qmldirSourcePath);
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
Utils::PathString directoryPath = m_pathCache.sourceContextPath(directoryId);
auto state = fileState(qmlDirSourceId, auto state = fileState(qmlDirSourceId,
package.fileStatuses, package.fileStatuses,
@@ -226,11 +228,11 @@ void ProjectStorageUpdater::updateQmldirs(const QStringList &qmlDirs,
package.updatedSourceIds.push_back(qmlDirSourceId); package.updatedSourceIds.push_back(qmlDirSourceId);
SourceContextId directoryId = m_pathCache.sourceContextId(qmlDirSourceId);
Utils::PathString moduleName{parser.typeNamespace()}; Utils::PathString moduleName{parser.typeNamespace()};
ModuleId moduleId = m_projectStorage.moduleId(moduleName); ModuleId moduleId = m_projectStorage.moduleId(moduleName);
ModuleId cppModuleId = m_projectStorage.moduleId(moduleName + "-cppnative"); ModuleId cppModuleId = m_projectStorage.moduleId(moduleName + "-cppnative");
ModuleId pathModuleId = m_projectStorage.moduleId(directoryPath);
auto imports = filterMultipleEntries(parser.imports()); auto imports = filterMultipleEntries(parser.imports());
@@ -252,7 +254,7 @@ void ProjectStorageUpdater::updateQmldirs(const QStringList &qmlDirs,
filterMultipleEntries(parser.dependencies()), filterMultipleEntries(parser.dependencies()),
imports, imports,
qmlDirSourceId, qmlDirSourceId,
directoryId, directoryPath,
cppModuleId, cppModuleId,
package, package,
notUpdatedFileStatusSourceIds, notUpdatedFileStatusSourceIds,
@@ -262,6 +264,7 @@ void ProjectStorageUpdater::updateQmldirs(const QStringList &qmlDirs,
qmlDirSourceId, qmlDirSourceId,
directoryId, directoryId,
moduleId, moduleId,
pathModuleId,
package, package,
notUpdatedFileStatusSourceIds); notUpdatedFileStatusSourceIds);
package.updatedProjectSourceIds.push_back(qmlDirSourceId); package.updatedProjectSourceIds.push_back(qmlDirSourceId);
@@ -270,7 +273,7 @@ void ProjectStorageUpdater::updateQmldirs(const QStringList &qmlDirs,
case FileState::NotChanged: { case FileState::NotChanged: {
const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId); const auto qmlProjectDatas = m_projectStorage.fetchProjectDatas(qmlDirSourceId);
parseTypeInfos(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds); parseTypeInfos(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, notUpdatedSourceIds);
parseQmlComponents(qmlProjectDatas, package, notUpdatedFileStatusSourceIds); parseQmlComponents(qmlProjectDatas, package, notUpdatedFileStatusSourceIds, directoryPath);
break; break;
} }
case FileState::NotExists: { case FileState::NotExists: {
@@ -292,17 +295,16 @@ void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos,
const QList<QmlDirParser::Import> &qmldirDependencies, const QList<QmlDirParser::Import> &qmldirDependencies,
const QList<QmlDirParser::Import> &qmldirImports, const QList<QmlDirParser::Import> &qmldirImports,
SourceId qmldirSourceId, SourceId qmldirSourceId,
SourceContextId directoryId, Utils::SmallStringView directoryPath,
ModuleId moduleId, ModuleId moduleId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds, SourceIds &notUpdatedFileStatusSourceIds,
SourceIds &notUpdatedSourceIds) SourceIds &notUpdatedSourceIds)
{ {
const Utils::PathString directory{m_pathCache.sourceContextPath(directoryId)};
for (const QString &typeInfo : typeInfos) { for (const QString &typeInfo : typeInfos) {
Utils::PathString qmltypesPath = Utils::PathString::join( Utils::PathString qmltypesPath = Utils::PathString::join(
{directory, "/", Utils::SmallString{typeInfo}}); {directoryPath, "/", Utils::SmallString{typeInfo}});
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmltypesPath}); SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmltypesPath});
addDependencies(package.moduleDependencies, addDependencies(package.moduleDependencies,
@@ -373,7 +375,7 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::ProjectData &projectDat
} }
void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFilePath, void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFilePath,
Utils::SmallStringView directory, Utils::SmallStringView directoryPath,
Storage::ExportedTypes exportedTypes, Storage::ExportedTypes exportedTypes,
ModuleId moduleId, ModuleId moduleId,
SourceId qmldirSourceId, SourceId qmldirSourceId,
@@ -383,7 +385,7 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
if (std::find(relativeFilePath.begin(), relativeFilePath.end(), '+') != relativeFilePath.end()) if (std::find(relativeFilePath.begin(), relativeFilePath.end(), '+') != relativeFilePath.end())
return; return;
Utils::PathString qmlFilePath = Utils::PathString::join({directory, "/", relativeFilePath}); Utils::PathString qmlFilePath = Utils::PathString::join({directoryPath, "/", relativeFilePath});
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmlFilePath}); SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmlFilePath});
Storage::Type type; Storage::Type type;
@@ -400,7 +402,7 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
throw CannotParseQmlDocumentFile{}; throw CannotParseQmlDocumentFile{};
case FileState::Changed: case FileState::Changed:
const auto content = m_fileSystem.contentAsQString(QString{qmlFilePath}); const auto content = m_fileSystem.contentAsQString(QString{qmlFilePath});
type = m_qmlDocumentParser.parse(content, package.imports, sourceId); type = m_qmlDocumentParser.parse(content, package.imports, sourceId, directoryPath);
break; break;
} }
@@ -418,6 +420,7 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView fileName, void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView filePath, Utils::SmallStringView filePath,
Utils::SmallStringView directoryPath,
SourceId sourceId, SourceId sourceId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds) SourceIds &notUpdatedFileStatusSourceIds)
@@ -434,7 +437,7 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView fileName,
SourcePath sourcePath{filePath}; SourcePath sourcePath{filePath};
const auto content = m_fileSystem.contentAsQString(QString{filePath}); const auto content = m_fileSystem.contentAsQString(QString{filePath});
auto type = m_qmlDocumentParser.parse(content, package.imports, sourceId); auto type = m_qmlDocumentParser.parse(content, package.imports, sourceId, directoryPath);
type.typeName = fileName; type.typeName = fileName;
type.accessSemantics = Storage::TypeAccessSemantics::Reference; type.accessSemantics = Storage::TypeAccessSemantics::Reference;
@@ -483,14 +486,28 @@ void partitionForTheSameFileName(const ComponentReferences &components, Callback
} }
} }
Storage::ExportedTypes filterExportedTypes(ComponentReferencesRange components, ModuleId moduleId) Storage::ExportedTypes createExportedTypes(ComponentReferencesRange components,
ModuleId moduleId,
Utils::SmallStringView fileName,
ModuleId pathModuleId)
{ {
return Utils::transform<Storage::ExportedTypes>(components, [&](ComponentReference component) { Storage::ExportedTypes exportedTypes;
return Storage::ExportedType{moduleId, exportedTypes.reserve(components.size() + 1);
Utils::SmallString{component.get().typeName},
Storage::Version{component.get().majorVersion, for (ComponentReference component : components) {
component.get().minorVersion}}; exportedTypes.emplace_back(moduleId,
}); Utils::SmallString{component.get().typeName},
Storage::Version{component.get().majorVersion,
component.get().minorVersion});
}
auto foundDot = std::find(fileName.begin(), fileName.end(), '.');
exportedTypes.emplace_back(pathModuleId,
Utils::SmallStringView{fileName.begin(), foundDot},
Storage::Version{});
return exportedTypes;
} }
} // namespace } // namespace
@@ -499,6 +516,7 @@ void ProjectStorageUpdater::parseQmlComponents(ComponentReferences components,
SourceId qmldirSourceId, SourceId qmldirSourceId,
SourceContextId directoryId, SourceContextId directoryId,
ModuleId moduleId, ModuleId moduleId,
ModuleId pathModuleId,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds) SourceIds &notUpdatedFileStatusSourceIds)
{ {
@@ -513,13 +531,14 @@ void ProjectStorageUpdater::parseQmlComponents(ComponentReferences components,
second.get().minorVersion); second.get().minorVersion);
}); });
auto directory = m_pathCache.sourceContextPath(directoryId); auto directoryPath = m_pathCache.sourceContextPath(directoryId);
auto callback = [&](ComponentReferencesRange componentsWithSameFileName) { auto callback = [&](ComponentReferencesRange componentsWithSameFileName) {
const auto &firstComponent = *componentsWithSameFileName.begin(); const auto &firstComponent = *componentsWithSameFileName.begin();
parseQmlComponent(Utils::SmallString{firstComponent.get().fileName}, const Utils::SmallString fileName{firstComponent.get().fileName};
directory, parseQmlComponent(fileName,
filterExportedTypes(componentsWithSameFileName, moduleId), directoryPath,
createExportedTypes(componentsWithSameFileName, moduleId, fileName, pathModuleId),
moduleId, moduleId,
qmldirSourceId, qmldirSourceId,
package, package,
@@ -531,7 +550,8 @@ void ProjectStorageUpdater::parseQmlComponents(ComponentReferences components,
void ProjectStorageUpdater::parseQmlComponents(const Storage::ProjectDatas &projectDatas, void ProjectStorageUpdater::parseQmlComponents(const Storage::ProjectDatas &projectDatas,
Storage::SynchronizationPackage &package, Storage::SynchronizationPackage &package,
SourceIds &notUpdatedFileStatusSourceIds) SourceIds &notUpdatedFileStatusSourceIds,
Utils::SmallStringView directoryPath)
{ {
for (const Storage::ProjectData &projectData : projectDatas) { for (const Storage::ProjectData &projectData : projectDatas) {
if (projectData.fileType != Storage::FileType::QmlDocument) if (projectData.fileType != Storage::FileType::QmlDocument)
@@ -541,6 +561,7 @@ void ProjectStorageUpdater::parseQmlComponents(const Storage::ProjectDatas &proj
parseQmlComponent(qmlDocumentPath.name(), parseQmlComponent(qmlDocumentPath.name(),
qmlDocumentPath, qmlDocumentPath,
directoryPath,
projectData.sourceId, projectData.sourceId,
package, package,
notUpdatedFileStatusSourceIds); notUpdatedFileStatusSourceIds);

View File

@@ -1022,31 +1022,31 @@ TEST_F(ProjectStorageUpdater, DontSynchronizeSelectors)
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithRelativeFilePath) TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithRelativeFilePath)
{ {
SourceId qmlDocumentSourceId = sourcePathCache.sourceId("/path/qml/First.qml"); SourceId qmlDocumentSourceId = sourcePathCache.sourceId("/path/First.qml");
ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId))) ON_CALL(fileSystemMock, fileStatus(Eq(qmlDocumentSourceId)))
.WillByDefault(Return(FileStatus{qmlDocumentSourceId, 22, 12})); .WillByDefault(Return(FileStatus{qmlDocumentSourceId, 22, 12}));
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qml/First.qml")))) ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/First.qml"))))
.WillByDefault(Return(qmlDocument1)); .WillByDefault(Return(qmlDocument1));
QString qmldir{R"(module Example QString qmldir{R"(module Example
FirstType 1.0 qml/First.qml FirstType 1.0 First.qml
FirstType2 1.0 qml/First.qml)"}; FirstType2 1.0 First.qml)"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir)); ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/qmldir")))).WillByDefault(Return(qmldir));
EXPECT_CALL(projectStorageMock, EXPECT_CALL(projectStorageMock,
synchronize( synchronize(
AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)), AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
Field(&SynchronizationPackage::types, Field(&SynchronizationPackage::types,
UnorderedElementsAre(AllOf( UnorderedElementsAre(
IsStorageType("First.qml", AllOf(IsStorageType("First.qml",
Storage::ImportedType{"Object"}, Storage::ImportedType{"Object"},
TypeAccessSemantics::Reference, TypeAccessSemantics::Reference,
qmlDocumentSourceId, qmlDocumentSourceId,
Storage::ChangeLevel::Full), Storage::ChangeLevel::Full),
Field(&Storage::Type::exportedTypes, Field(&Storage::Type::exportedTypes,
UnorderedElementsAre( UnorderedElementsAre(
IsExportedType(exampleModuleId, "FirstType", 1, 0), IsExportedType(exampleModuleId, "FirstType", 1, 0),
IsExportedType(exampleModuleId, "FirstType2", 1, 0), IsExportedType(exampleModuleId, "FirstType2", 1, 0),
IsExportedType(subPathQmlModuleId, "First", -1, -1)))))), IsExportedType(pathModuleId, "First", -1, -1)))))),
Field(&SynchronizationPackage::updatedSourceIds, Field(&SynchronizationPackage::updatedSourceIds,
UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId)), UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId)),
Field(&SynchronizationPackage::updatedFileStatusSourceIds, Field(&SynchronizationPackage::updatedFileStatusSourceIds,