QmlJS: Fix Follow under cursor

When trying to jump to a symbol in a qml file the Qml Model may find
the location in a generated .qml file in the build folder.
QtCreator searches in all generated .qrc files to try and find
the source file so it can jump to it instead.

Previously not all auto-generated ".rcc" folders would be found
as only the folders of targets (executables) were searched.
Plugins or Static Libraries were not searched.

With this fix, all projects nodes are searched for the ".rcc" folder
and therefore also finds them for Dynamic / Static libraries and
plugins.

Fixes: QTCREATORBUG-27173
Change-Id: Ic51ac8fbc82c15785cbefd76787942a512ecf3db
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2022-10-25 08:57:49 +02:00
parent fe376af66b
commit 129448d61d
11 changed files with 67 additions and 27 deletions

View File

@@ -432,15 +432,13 @@ bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1,
} }
static QList<Utils::FilePath> generatedQrc(QList<Utils::FilePath> applicationDirectories) static QSet<Utils::FilePath> generatedQrc(
const QList<ModelManagerInterface::ProjectInfo> &projectInfos)
{ {
QList<Utils::FilePath> res; QSet<Utils::FilePath> res;
for (const Utils::FilePath &path : applicationDirectories) { for (const auto &pInfo : projectInfos) {
Utils::FilePath generatedQrcDir = path.pathAppended(".rcc"); for (const auto &generatedQrcFile: pInfo.generatedQrcFiles)
if (generatedQrcDir.isReadableDir()) { res.insert(generatedQrcFile);
for (const Utils::FilePath & qrcPath: generatedQrcDir.dirEntries(FileFilter(QStringList({QStringLiteral(u"*.qrc")}), QDir::Files)))
res.append(qrcPath.canonicalPath());
}
} }
return res; return res;
} }
@@ -467,7 +465,7 @@ void ModelManagerInterface::iterateQrcFiles(
qrcFilePaths = pInfo.activeResourceFiles; qrcFilePaths = pInfo.activeResourceFiles;
else else
qrcFilePaths = pInfo.allResourceFiles; qrcFilePaths = pInfo.allResourceFiles;
for (const Utils::FilePath &p : generatedQrc(pInfo.applicationDirectories)) for (const Utils::FilePath &p : generatedQrc({pInfo}))
qrcFilePaths.append(p); qrcFilePaths.append(p);
for (const Utils::FilePath &qrcFilePath : std::as_const(qrcFilePaths)) { for (const Utils::FilePath &qrcFilePath : std::as_const(qrcFilePaths)) {
if (pathsChecked.contains(qrcFilePath)) if (pathsChecked.contains(qrcFilePath))
@@ -590,7 +588,7 @@ void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectE
m_qrcContents = pinfo.resourceFileContents; m_qrcContents = pinfo.resourceFileContents;
for (const Utils::FilePath &newQrc : std::as_const(pinfo.allResourceFiles)) for (const Utils::FilePath &newQrc : std::as_const(pinfo.allResourceFiles))
m_qrcCache.addPath(newQrc.toString(), m_qrcContents.value(newQrc)); m_qrcCache.addPath(newQrc.toString(), m_qrcContents.value(newQrc));
for (const Utils::FilePath &newQrc : generatedQrc(pinfo.applicationDirectories)) for (const Utils::FilePath &newQrc : pinfo.generatedQrcFiles)
m_qrcCache.addPath(newQrc.toString(), m_qrcContents.value(newQrc)); m_qrcCache.addPath(newQrc.toString(), m_qrcContents.value(newQrc));
for (const Utils::FilePath &oldQrc : std::as_const(oldInfo.allResourceFiles)) for (const Utils::FilePath &oldQrc : std::as_const(oldInfo.allResourceFiles))
m_qrcCache.removePath(oldQrc.toString()); m_qrcCache.removePath(oldQrc.toString());
@@ -1293,7 +1291,7 @@ void ModelManagerInterface::updateImportPaths()
allImportPaths.maybeInsert(path, Dialect::Qml); allImportPaths.maybeInsert(path, Dialect::Qml);
findNewQmlApplicationInPath(path, snapshot, this, &newLibraries); findNewQmlApplicationInPath(path, snapshot, this, &newLibraries);
} }
for (const Utils::FilePath &qrcPath : generatedQrc(allApplicationDirectories)) for (const Utils::FilePath &qrcPath : generatedQrc(m_projects.values()))
updateQrcFile(qrcPath); updateQrcFile(qrcPath);
updateSourceFiles(importedFiles, true); updateSourceFiles(importedFiles, true);
@@ -1625,8 +1623,10 @@ ModelManagerInterface::ProjectInfo ModelManagerInterface::defaultProjectInfo() c
} }
ModelManagerInterface::ProjectInfo ModelManagerInterface::defaultProjectInfoForProject( ModelManagerInterface::ProjectInfo ModelManagerInterface::defaultProjectInfoForProject(
ProjectExplorer::Project *) const ProjectExplorer::Project *project, const FilePaths &hiddenRccFolders) const
{ {
Q_UNUSED(project);
Q_UNUSED(hiddenRccFolders);
return ModelManagerInterface::ProjectInfo(); return ModelManagerInterface::ProjectInfo();
} }

View File

@@ -51,6 +51,7 @@ public:
PathsAndLanguages importPaths; PathsAndLanguages importPaths;
QList<Utils::FilePath> activeResourceFiles; QList<Utils::FilePath> activeResourceFiles;
QList<Utils::FilePath> allResourceFiles; QList<Utils::FilePath> allResourceFiles;
QList<Utils::FilePath> generatedQrcFiles;
QHash<Utils::FilePath, QString> resourceFileContents; QHash<Utils::FilePath, QString> resourceFileContents;
QList<Utils::FilePath> applicationDirectories; QList<Utils::FilePath> applicationDirectories;
QHash<QString, QString> moduleMappings; // E.g.: QtQuick.Controls -> MyProject.MyControls QHash<QString, QString> moduleMappings; // E.g.: QtQuick.Controls -> MyProject.MyControls
@@ -164,8 +165,8 @@ public:
void setDefaultVContext(const ViewerContext &vContext); void setDefaultVContext(const ViewerContext &vContext);
virtual ProjectInfo defaultProjectInfo() const; virtual ProjectInfo defaultProjectInfo() const;
virtual ProjectInfo defaultProjectInfoForProject(ProjectExplorer::Project *project) const; virtual ProjectInfo defaultProjectInfoForProject(ProjectExplorer::Project *project,
const Utils::FilePaths &hiddenRccFolders) const;
// Blocks until all parsing threads are done. Use for testing only! // Blocks until all parsing threads are done. Use for testing only!
void test_joinAllThreads(); void test_joinAllThreads();

View File

@@ -1186,8 +1186,8 @@ void CMakeBuildSystem::updateQmlJSCodeModel(const QStringList &extraHeaderPaths,
return; return;
Project *p = project(); Project *p = project();
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = modelManager QmlJS::ModelManagerInterface::ProjectInfo projectInfo
->defaultProjectInfoForProject(p); = modelManager->defaultProjectInfoForProject(p, p->files(Project::HiddenRccFolders));
projectInfo.importPaths.clear(); projectInfo.importPaths.clear();

View File

@@ -109,6 +109,10 @@ const Project::NodeMatcher Project::GeneratedFiles = [](const Node *node) {
return isListedFileNode(node) && node->isGenerated(); return isListedFileNode(node) && node->isGenerated();
}; };
const Project::NodeMatcher Project::HiddenRccFolders = [](const Node *node) {
return node->isFolderNodeType() && node->filePath().fileName() == ".rcc";
};
// -------------------------------------------------------------------- // --------------------------------------------------------------------
// ProjectDocument: // ProjectDocument:
// -------------------------------------------------------------------- // --------------------------------------------------------------------

View File

@@ -101,6 +101,7 @@ public:
static const NodeMatcher AllFiles; static const NodeMatcher AllFiles;
static const NodeMatcher SourceFiles; static const NodeMatcher SourceFiles;
static const NodeMatcher GeneratedFiles; static const NodeMatcher GeneratedFiles;
static const NodeMatcher HiddenRccFolders;
Utils::FilePaths files(const NodeMatcher &matcher) const; Utils::FilePaths files(const NodeMatcher &matcher) const;
bool isKnownFile(const Utils::FilePath &filename) const; bool isKnownFile(const Utils::FilePath &filename) const;

View File

@@ -250,7 +250,8 @@ void PythonBuildSystem::triggerParsing()
auto modelManager = QmlJS::ModelManagerInterface::instance(); auto modelManager = QmlJS::ModelManagerInterface::instance();
if (modelManager) { if (modelManager) {
auto projectInfo = modelManager->defaultProjectInfoForProject(project()); const auto hiddenRccFolders = project()->files(Project::HiddenRccFolders);
auto projectInfo = modelManager->defaultProjectInfoForProject(project(), hiddenRccFolders);
for (const QString &importPath : std::as_const(m_qmlImportPaths)) { for (const QString &importPath : std::as_const(m_qmlImportPaths)) {
const FilePath filePath = FilePath::fromString(importPath); const FilePath filePath = FilePath::fromString(importPath);

View File

@@ -1052,8 +1052,9 @@ void QbsBuildSystem::updateQmlJsCodeModel()
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
if (!modelManager) if (!modelManager)
return; return;
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = QmlJS::ModelManagerInterface::ProjectInfo projectInfo
modelManager->defaultProjectInfoForProject(project()); = modelManager->defaultProjectInfoForProject(project(),
project()->files(Project::HiddenRccFolders));
const QJsonObject projectData = session()->projectData(); const QJsonObject projectData = session()->projectData();
if (projectData.isEmpty()) if (projectData.isEmpty())

View File

@@ -410,8 +410,9 @@ void QmakeBuildSystem::updateQmlJSCodeModel()
if (!modelManager) if (!modelManager)
return; return;
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = QmlJS::ModelManagerInterface::ProjectInfo projectInfo
modelManager->defaultProjectInfoForProject(project()); = modelManager->defaultProjectInfoForProject(project(),
project()->files(Project::HiddenRccFolders));
const QList<QmakeProFile *> proFiles = rootProFile()->allProFiles(); const QList<QmakeProFile *> proFiles = rootProFile()->allProFiles();

View File

@@ -81,8 +81,36 @@ static void setupProjectInfoQmlBundles(ModelManagerInterface::ProjectInfo &proje
} }
} }
static void findAllQrcFiles(const FilePath &filePath, FilePaths &out)
{
filePath.iterateDirectory(
[&out](const FilePath &path) {
out.append(path.canonicalPath());
return true;
},
{{"*.qrc"}, QDir::Files});
}
static FilePaths findGeneratedQrcFiles(const ModelManagerInterface::ProjectInfo &pInfo,
const FilePaths &hiddenRccFolders)
{
FilePaths result;
// Search in Application Directories for directories named ".rcc"
// and add all .qrc files in there to the resource file list.
for (const Utils::FilePath &path : pInfo.applicationDirectories) {
Utils::FilePath generatedQrcDir = path.pathAppended(".rcc");
findAllQrcFiles(generatedQrcDir, result);
}
for (const Utils::FilePath &hiddenRccFolder : hiddenRccFolders) {
findAllQrcFiles(hiddenRccFolder, result);
}
return result;
}
ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject( ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
Project *project) const Project *project, const FilePaths &hiddenRccFolders) const
{ {
ModelManagerInterface::ProjectInfo projectInfo; ModelManagerInterface::ProjectInfo projectInfo;
projectInfo.project = project; projectInfo.project = project;
@@ -183,6 +211,7 @@ ModelManagerInterface::ProjectInfo ModelManager::defaultProjectInfoForProject(
} }
setupProjectInfoQmlBundles(projectInfo); setupProjectInfoQmlBundles(projectInfo);
projectInfo.generatedQrcFiles = findGeneratedQrcFiles(projectInfo, hiddenRccFolders);
return projectInfo; return projectInfo;
} }
@@ -294,7 +323,7 @@ void ModelManager::updateDefaultProjectInfo()
Project *currentProject = SessionManager::startupProject(); Project *currentProject = SessionManager::startupProject();
setDefaultProject(containsProject(currentProject) setDefaultProject(containsProject(currentProject)
? projectInfo(currentProject) ? projectInfo(currentProject)
: defaultProjectInfoForProject(currentProject), : defaultProjectInfoForProject(currentProject, {}),
currentProject); currentProject);
} }

View File

@@ -32,7 +32,8 @@ protected:
WorkingCopy workingCopyInternal() const override; WorkingCopy workingCopyInternal() const override;
void addTaskInternal(const QFuture<void> &result, const QString &msg, void addTaskInternal(const QFuture<void> &result, const QString &msg,
const char *taskId) const override; const char *taskId) const override;
ProjectInfo defaultProjectInfoForProject(ProjectExplorer::Project *project) const override; ProjectInfo defaultProjectInfoForProject(
ProjectExplorer::Project *project, const Utils::FilePaths &hiddenRccFolders) const override;
private: private:
void updateDefaultProjectInfo(); void updateDefaultProjectInfo();
void loadDefaultQmlTypeDescriptions(); void loadDefaultQmlTypeDescriptions();

View File

@@ -312,8 +312,9 @@ void QmlBuildSystem::refresh(RefreshOptions options)
if (!modelManager) if (!modelManager)
return; return;
QmlJS::ModelManagerInterface::ProjectInfo projectInfo = QmlJS::ModelManagerInterface::ProjectInfo projectInfo
modelManager->defaultProjectInfoForProject(project()); = modelManager->defaultProjectInfoForProject(project(),
project()->files(Project::HiddenRccFolders));
const QStringList searchPaths = makeAbsolute(canonicalProjectDir(), customImportPaths()); const QStringList searchPaths = makeAbsolute(canonicalProjectDir(), customImportPaths());
for (const QString &searchPath : searchPaths) for (const QString &searchPath : searchPaths)
projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(searchPath), projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(searchPath),