forked from qt-creator/qt-creator
CppEditor: Speed up findFilesInProject()
This function had a number of serious performance problems. As it is executed by several quickfix factories, it could cause freezes on right- clicking a symbol. Measures taken: - Check file type before file path. - Do not collect all files in the project first, but filter earlier. - Check all candidate file names at once. In an example project, I observed a speed-up of factor ~100. Some FilePath-ification was done as well. Task-number: QTCREATORBUG-29611 Change-Id: Ic5dc48ffd86f22263d1caea4b6bfea5f49e589a4 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -668,25 +668,20 @@ void CppEditorPlugin::setGlobalFileSettings(const CppFileSettings &settings)
|
||||
}
|
||||
#endif
|
||||
|
||||
static QStringList findFilesInProject(const QString &name, const Project *project)
|
||||
static FilePaths findFilesInProject(const QStringList &names, const Project *project,
|
||||
FileType fileType)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << Q_FUNC_INFO << name << project;
|
||||
qDebug() << Q_FUNC_INFO << names << project;
|
||||
|
||||
if (!project)
|
||||
return {};
|
||||
|
||||
QString pattern = QString(1, QLatin1Char('/'));
|
||||
pattern += name;
|
||||
const QStringList projectFiles
|
||||
= transform(project->files(Project::AllFiles), &FilePath::toString);
|
||||
const QStringList::const_iterator pcend = projectFiles.constEnd();
|
||||
QStringList candidateList;
|
||||
for (QStringList::const_iterator it = projectFiles.constBegin(); it != pcend; ++it) {
|
||||
if (it->endsWith(pattern, HostOsInfo::fileNameCaseSensitivity()))
|
||||
candidateList.append(*it);
|
||||
}
|
||||
return candidateList;
|
||||
const auto filter = [&](const Node *n) {
|
||||
const auto fn = n->asFileNode();
|
||||
return fn && fn->fileType() == fileType && names.contains(fn->filePath().fileName());
|
||||
};
|
||||
return project->files(filter);
|
||||
}
|
||||
|
||||
// Return the suffixes that should be checked when trying to find a
|
||||
@@ -778,30 +773,31 @@ static int commonFilePathLength(const QString &s1, const QString &s2)
|
||||
static FilePath correspondingHeaderOrSourceInProject(const QFileInfo &fileInfo,
|
||||
const QStringList &candidateFileNames,
|
||||
const Project *project,
|
||||
FileType fileType,
|
||||
CacheUsage cacheUsage)
|
||||
{
|
||||
QString bestFileName;
|
||||
int compareValue = 0;
|
||||
const QString filePath = fileInfo.filePath();
|
||||
for (const QString &candidateFileName : candidateFileNames) {
|
||||
const QStringList projectFiles = findFilesInProject(candidateFileName, project);
|
||||
// Find the file having the most common path with fileName
|
||||
for (const QString &projectFile : projectFiles) {
|
||||
int value = commonFilePathLength(filePath, projectFile);
|
||||
if (value > compareValue) {
|
||||
compareValue = value;
|
||||
bestFileName = projectFile;
|
||||
}
|
||||
const FilePaths projectFiles = findFilesInProject(candidateFileNames, project, fileType);
|
||||
|
||||
// Find the file having the most common path with fileName
|
||||
FilePath bestFilePath;
|
||||
int compareValue = 0;
|
||||
for (const FilePath &projectFile : projectFiles) {
|
||||
int value = commonFilePathLength(filePath, projectFile.toString());
|
||||
if (value > compareValue) {
|
||||
compareValue = value;
|
||||
bestFilePath = projectFile;
|
||||
}
|
||||
}
|
||||
if (!bestFileName.isEmpty()) {
|
||||
const QFileInfo candidateFi(bestFileName);
|
||||
QTC_ASSERT(candidateFi.isFile(), return {});
|
||||
if (!bestFilePath.isEmpty()) {
|
||||
QTC_ASSERT(bestFilePath.isFile(), return {});
|
||||
if (cacheUsage == CacheUsage::ReadWrite) {
|
||||
m_headerSourceMapping[fileInfo.absoluteFilePath()] = candidateFi.absoluteFilePath();
|
||||
m_headerSourceMapping[candidateFi.absoluteFilePath()] = fileInfo.absoluteFilePath();
|
||||
m_headerSourceMapping[fileInfo.absoluteFilePath()]
|
||||
= bestFilePath.absoluteFilePath().toString();
|
||||
m_headerSourceMapping[bestFilePath.absoluteFilePath().toString()]
|
||||
= fileInfo.absoluteFilePath();
|
||||
}
|
||||
return FilePath::fromString(candidateFi.absoluteFilePath());
|
||||
return bestFilePath;
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -878,9 +874,10 @@ FilePath correspondingHeaderOrSource(const FilePath &filePath, bool *wasHeader,
|
||||
Project *currentProject = projectForFile;
|
||||
if (!projectForFile)
|
||||
currentProject = ProjectTree::currentProject();
|
||||
const FileType requestedFileType = isHeader ? FileType::Source : FileType::Header;
|
||||
if (currentProject) {
|
||||
const FilePath path = correspondingHeaderOrSourceInProject(fi, candidateFileNames,
|
||||
currentProject, cacheUsage);
|
||||
const FilePath path = correspondingHeaderOrSourceInProject(
|
||||
fi, candidateFileNames, currentProject, requestedFileType, cacheUsage);
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
|
||||
@@ -892,8 +889,8 @@ FilePath correspondingHeaderOrSource(const FilePath &filePath, bool *wasHeader,
|
||||
if (project == currentProject)
|
||||
continue; // We have already checked the current project.
|
||||
|
||||
const FilePath path = correspondingHeaderOrSourceInProject(fi, candidateFileNames,
|
||||
project, cacheUsage);
|
||||
const FilePath path = correspondingHeaderOrSourceInProject(
|
||||
fi, candidateFileNames, project, requestedFileType, cacheUsage);
|
||||
if (!path.isEmpty())
|
||||
return path;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user