FileApiReader: Make shutdown faster

Check more often for canceled future.

Make more functions static.

Fixes: QTCREATORBUG-27729
Change-Id: I8dd787acea6343008c7515fb6a4fdfde50b37aee
Reviewed-by: Cristian Adam <cristian.adam@qt.io>
This commit is contained in:
Jarek Kobus
2023-10-06 14:47:46 +02:00
parent e4ae894c96
commit ee48dba19e
3 changed files with 243 additions and 184 deletions

View File

@@ -12,10 +12,10 @@
#include <cppeditor/cppeditorconstants.h> #include <cppeditor/cppeditorconstants.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/icon.h>
#include <utils/mimeutils.h> #include <utils/mimeutils.h>
#include <utils/process.h> #include <utils/process.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/icon.h>
#include <projectexplorer/projecttree.h> #include <projectexplorer/projecttree.h>
@@ -45,14 +45,13 @@ public:
std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeListNodes; std::vector<std::unique_ptr<ProjectExplorer::FileNode>> cmakeListNodes;
}; };
CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefiles, static CMakeFileResult extractCMakeFilesData(const QFuture<void> &cancelFuture,
const std::vector<CMakeFileInfo> &cmakefiles,
const FilePath &sourceDirectory, const FilePath &sourceDirectory,
const FilePath &buildDirectory) const FilePath &buildDirectory)
{ {
CMakeFileResult result;
if (cmakefiles.empty()) if (cmakefiles.empty())
return result; return {};
// Uniquify fileInfos // Uniquify fileInfos
std::set<CMakeFileInfo> cmakeFileSet{cmakefiles.begin(), cmakefiles.end()}; std::set<CMakeFileInfo> cmakeFileSet{cmakefiles.begin(), cmakefiles.end()};
@@ -60,7 +59,9 @@ CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefil
// Load and parse cmake files. We use concurrency here to speed up the process of // Load and parse cmake files. We use concurrency here to speed up the process of
// reading many small files, which can get slow especially on remote devices. // reading many small files, which can get slow especially on remote devices.
QFuture<CMakeFileInfo> mapResult QFuture<CMakeFileInfo> mapResult
= QtConcurrent::mapped(cmakeFileSet, [sourceDirectory](const auto &info) { = QtConcurrent::mapped(cmakeFileSet, [cancelFuture, sourceDirectory](const auto &info) {
if (cancelFuture.isCanceled())
return CMakeFileInfo();
const FilePath sfn = sourceDirectory.resolvePath(info.path); const FilePath sfn = sourceDirectory.resolvePath(info.path);
CMakeFileInfo absolute(info); CMakeFileInfo absolute(info);
absolute.path = sfn; absolute.path = sfn;
@@ -86,7 +87,15 @@ CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefil
mapResult.waitForFinished(); mapResult.waitForFinished();
if (cancelFuture.isCanceled())
return {};
CMakeFileResult result;
for (const auto &info : mapResult.results()) { for (const auto &info : mapResult.results()) {
if (cancelFuture.isCanceled())
return {};
result.cmakeFiles.insert(info); result.cmakeFiles.insert(info);
if (info.isCMake && !info.isCMakeListsDotTxt) { if (info.isCMake && !info.isCMakeListsDotTxt) {
@@ -132,22 +141,17 @@ public:
std::vector<TargetDetails> targetDetails; std::vector<TargetDetails> targetDetails;
}; };
PreprocessedData preprocess(FileApiData &data, static PreprocessedData preprocess(const QFuture<void> &cancelFuture, FileApiData &data,
const FilePath &sourceDirectory, const FilePath &sourceDirectory, const FilePath &buildDirectory)
const FilePath &buildDirectory,
QString &errorMessage)
{ {
Q_UNUSED(errorMessage)
PreprocessedData result; PreprocessedData result;
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
result.codemodel = std::move(data.codemodel); result.codemodel = std::move(data.codemodel);
CMakeFileResult cmakeFileResult = extractCMakeFilesData(data.cmakeFiles, CMakeFileResult cmakeFileResult = extractCMakeFilesData(cancelFuture, data.cmakeFiles,
sourceDirectory, sourceDirectory, buildDirectory);
buildDirectory);
result.cmakeFiles = std::move(cmakeFileResult.cmakeFiles); result.cmakeFiles = std::move(cmakeFileResult.cmakeFiles);
result.cmakeNodesSource = std::move(cmakeFileResult.cmakeNodesSource); result.cmakeNodesSource = std::move(cmakeFileResult.cmakeNodesSource);
@@ -160,7 +164,8 @@ PreprocessedData preprocess(FileApiData &data,
return result; return result;
} }
QVector<FolderNode::LocationInfo> extractBacktraceInformation(const BacktraceInfo &backtraces, static QVector<FolderNode::LocationInfo> extractBacktraceInformation(
const BacktraceInfo &backtraces,
const FilePath &sourceDir, const FilePath &sourceDir,
int backtraceIndex, int backtraceIndex,
unsigned int locationInfoPriority) unsigned int locationInfoPriority)
@@ -200,14 +205,11 @@ static bool isChildOf(const FilePath &path, const FilePaths &prefixes)
return false; return false;
} }
QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input, static CMakeBuildTarget toBuildTarget(const TargetDetails &t,
const FilePath &sourceDirectory, const FilePath &sourceDirectory,
const FilePath &buildDirectory, const FilePath &buildDirectory,
bool haveLibrariesRelativeToBuildDirectory) bool relativeLibs)
{ {
const QList<CMakeBuildTarget> result = transform<QList>(input.targetDetails,
[&sourceDirectory, &buildDirectory,
&haveLibrariesRelativeToBuildDirectory](const TargetDetails &t) {
const FilePath currentBuildDir = buildDirectory.resolvePath(t.buildDir); const FilePath currentBuildDir = buildDirectory.resolvePath(t.buildDir);
CMakeBuildTarget ct; CMakeBuildTarget ct;
@@ -293,7 +295,7 @@ QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input,
if (part.startsWith("-")) if (part.startsWith("-"))
continue; continue;
const FilePath buildDir = haveLibrariesRelativeToBuildDirectory ? buildDirectory : currentBuildDir; const FilePath buildDir = relativeLibs ? buildDirectory : currentBuildDir;
FilePath tmp = buildDir.resolvePath(part); FilePath tmp = buildDir.resolvePath(part);
if (f.role == "libraries") if (f.role == "libraries")
@@ -326,9 +328,22 @@ QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input,
} }
ct.libraryDirectories = filteredUnique(librarySeachPaths); ct.libraryDirectories = filteredUnique(librarySeachPaths);
} }
return ct; return ct;
}); }
static QList<CMakeBuildTarget> generateBuildTargets(const QFuture<void> &cancelFuture,
const PreprocessedData &input,
const FilePath &sourceDirectory,
const FilePath &buildDirectory,
bool relativeLibs)
{
QList<CMakeBuildTarget> result;
result.reserve(input.targetDetails.size());
for (const TargetDetails &t : input.targetDetails) {
if (cancelFuture.isCanceled())
return {};
result.append(toBuildTarget(t, sourceDirectory, buildDirectory, relativeLibs));
}
return result; return result;
} }
@@ -341,24 +356,28 @@ static QStringList splitFragments(const QStringList &fragments)
return result; return result;
} }
bool isPchFile(const FilePath &buildDirectory, const FilePath &path) static bool isPchFile(const FilePath &buildDirectory, const FilePath &path)
{ {
return path.isChildOf(buildDirectory) && path.fileName().startsWith("cmake_pch"); return path.isChildOf(buildDirectory) && path.fileName().startsWith("cmake_pch");
} }
bool isUnityFile(const FilePath &buildDirectory, const FilePath &path) static bool isUnityFile(const FilePath &buildDirectory, const FilePath &path)
{ {
return path.isChildOf(buildDirectory) && path.parentDir().fileName() == "Unity" return path.isChildOf(buildDirectory) && path.parentDir().fileName() == "Unity"
&& path.fileName().startsWith("unity_"); && path.fileName().startsWith("unity_");
} }
RawProjectParts generateRawProjectParts(const PreprocessedData &input, static RawProjectParts generateRawProjectParts(const QFuture<void> &cancelFuture,
const PreprocessedData &input,
const FilePath &sourceDirectory, const FilePath &sourceDirectory,
const FilePath &buildDirectory) const FilePath &buildDirectory)
{ {
RawProjectParts rpps; RawProjectParts rpps;
for (const TargetDetails &t : input.targetDetails) { for (const TargetDetails &t : input.targetDetails) {
if (cancelFuture.isCanceled())
return {};
bool needPostfix = t.compileGroups.size() > 1; bool needPostfix = t.compileGroups.size() > 1;
int count = 1; int count = 1;
for (const CompileInfo &ci : t.compileGroups) { for (const CompileInfo &ci : t.compileGroups) {
@@ -520,7 +539,9 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
return rpps; return rpps;
} }
FilePath directorySourceDir(const Configuration &c, const FilePath &sourceDir, int directoryIndex) static FilePath directorySourceDir(const Configuration &c,
const FilePath &sourceDir,
int directoryIndex)
{ {
const size_t di = static_cast<size_t>(directoryIndex); const size_t di = static_cast<size_t>(directoryIndex);
QTC_ASSERT(di < c.directories.size(), return {}); QTC_ASSERT(di < c.directories.size(), return {});
@@ -528,7 +549,9 @@ FilePath directorySourceDir(const Configuration &c, const FilePath &sourceDir, i
return sourceDir.resolvePath(c.directories[di].sourcePath); return sourceDir.resolvePath(c.directories[di].sourcePath);
} }
FilePath directoryBuildDir(const Configuration &c, const FilePath &buildDir, int directoryIndex) static FilePath directoryBuildDir(const Configuration &c,
const FilePath &buildDir,
int directoryIndex)
{ {
const size_t di = static_cast<size_t>(directoryIndex); const size_t di = static_cast<size_t>(directoryIndex);
QTC_ASSERT(di < c.directories.size(), return {}); QTC_ASSERT(di < c.directories.size(), return {});
@@ -536,11 +559,15 @@ FilePath directoryBuildDir(const Configuration &c, const FilePath &buildDir, int
return buildDir.resolvePath(c.directories[di].buildPath); return buildDir.resolvePath(c.directories[di].buildPath);
} }
void addProjects(const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes, static void addProjects(const QFuture<void> &cancelFuture,
const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
const Configuration &config, const Configuration &config,
const FilePath &sourceDir) const FilePath &sourceDir)
{ {
for (const FileApiDetails::Project &p : config.projects) { for (const FileApiDetails::Project &p : config.projects) {
if (cancelFuture.isCanceled())
return;
if (p.parent == -1) if (p.parent == -1)
continue; // Top-level project has already been covered continue; // Top-level project has already been covered
FilePath dir = directorySourceDir(config, sourceDir, p.directories[0]); FilePath dir = directorySourceDir(config, sourceDir, p.directories[0]);
@@ -548,7 +575,7 @@ void addProjects(const QHash<Utils::FilePath, ProjectNode *> &cmakeListsNodes,
} }
} }
FolderNode *createSourceGroupNode(const QString &sourceGroupName, static FolderNode *createSourceGroupNode(const QString &sourceGroupName,
const FilePath &sourceDirectory, const FilePath &sourceDirectory,
FolderNode *targetRoot) FolderNode *targetRoot)
{ {
@@ -576,7 +603,7 @@ FolderNode *createSourceGroupNode(const QString &sourceGroupName,
return currentNode; return currentNode;
} }
void addCompileGroups(ProjectNode *targetRoot, static void addCompileGroups(ProjectNode *targetRoot,
const Utils::FilePath &topSourceDirectory, const Utils::FilePath &topSourceDirectory,
const Utils::FilePath &sourceDirectory, const Utils::FilePath &sourceDirectory,
const Utils::FilePath &buildDirectory, const Utils::FilePath &buildDirectory,
@@ -683,7 +710,8 @@ static void addGeneratedFilesNode(ProjectNode *targetRoot, const FilePath &topLe
addCMakeVFolder(targetRoot, buildDir, 10, Tr::tr("<Generated Files>"), std::move(nodes)); addCMakeVFolder(targetRoot, buildDir, 10, Tr::tr("<Generated Files>"), std::move(nodes));
} }
void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cmakeListsNodes, static void addTargets(const QFuture<void> &cancelFuture,
const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cmakeListsNodes,
const Configuration &config, const Configuration &config,
const std::vector<TargetDetails> &targetDetails, const std::vector<TargetDetails> &targetDetails,
const FilePath &sourceDir, const FilePath &sourceDir,
@@ -702,6 +730,9 @@ void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cm
}; };
for (const FileApiDetails::Target &t : config.targets) { for (const FileApiDetails::Target &t : config.targets) {
if (cancelFuture.isCanceled())
return;
const TargetDetails &td = getTargetDetails(t.id); const TargetDetails &td = getTargetDetails(t.id);
const FilePath dir = directorySourceDir(config, sourceDir, t.directory); const FilePath dir = directorySourceDir(config, sourceDir, t.directory);
@@ -717,8 +748,10 @@ void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cm
} }
} }
std::unique_ptr<CMakeProjectNode> generateRootProjectNode( static std::unique_ptr<CMakeProjectNode> generateRootProjectNode(const QFuture<void> &cancelFuture,
PreprocessedData &data, const FilePath &sourceDirectory, const FilePath &buildDirectory) PreprocessedData &data,
const FilePath &sourceDirectory,
const FilePath &buildDirectory)
{ {
std::unique_ptr<CMakeProjectNode> result = std::make_unique<CMakeProjectNode>(sourceDirectory); std::unique_ptr<CMakeProjectNode> result = std::make_unique<CMakeProjectNode>(sourceDirectory);
@@ -733,25 +766,34 @@ std::unique_ptr<CMakeProjectNode> generateRootProjectNode(
std::move(data.cmakeListNodes)); std::move(data.cmakeListNodes));
data.cmakeListNodes.clear(); // Remove all the nullptr in the vector... data.cmakeListNodes.clear(); // Remove all the nullptr in the vector...
addProjects(cmakeListsNodes, data.codemodel, sourceDirectory); addProjects(cancelFuture, cmakeListsNodes, data.codemodel, sourceDirectory);
if (cancelFuture.isCanceled())
return {};
addTargets(cmakeListsNodes, addTargets(cancelFuture,
cmakeListsNodes,
data.codemodel, data.codemodel,
data.targetDetails, data.targetDetails,
sourceDirectory, sourceDirectory,
buildDirectory); buildDirectory);
if (cancelFuture.isCanceled())
return {};
if (!data.cmakeNodesSource.empty() || !data.cmakeNodesBuild.empty() if (!data.cmakeNodesSource.empty() || !data.cmakeNodesBuild.empty()
|| !data.cmakeNodesOther.empty()) || !data.cmakeNodesOther.empty()) {
addCMakeInputs(result.get(), addCMakeInputs(result.get(),
sourceDirectory, sourceDirectory,
buildDirectory, buildDirectory,
std::move(data.cmakeNodesSource), std::move(data.cmakeNodesSource),
std::move(data.cmakeNodesBuild), std::move(data.cmakeNodesBuild),
std::move(data.cmakeNodesOther)); std::move(data.cmakeNodesOther));
}
if (cancelFuture.isCanceled())
return {};
addCMakePresets(result.get(), sourceDirectory); addCMakePresets(result.get(), sourceDirectory);
if (cancelFuture.isCanceled())
return {};
data.cmakeNodesSource.clear(); // Remove all the nullptr in the vector... data.cmakeNodesSource.clear(); // Remove all the nullptr in the vector...
data.cmakeNodesBuild.clear(); // Remove all the nullptr in the vector... data.cmakeNodesBuild.clear(); // Remove all the nullptr in the vector...
@@ -760,7 +802,9 @@ std::unique_ptr<CMakeProjectNode> generateRootProjectNode(
return result; return result;
} }
void setupLocationInfoForTargets(CMakeProjectNode *rootNode, const QList<CMakeBuildTarget> &targets) static void setupLocationInfoForTargets(const QFuture<void> &cancelFuture,
CMakeProjectNode *rootNode,
const QList<CMakeBuildTarget> &targets)
{ {
const QSet<QString> titles = Utils::transform<QSet>(targets, &CMakeBuildTarget::title); const QSet<QString> titles = Utils::transform<QSet>(targets, &CMakeBuildTarget::title);
QHash<QString, FolderNode *> buildKeyToNode; QHash<QString, FolderNode *> buildKeyToNode;
@@ -771,6 +815,9 @@ void setupLocationInfoForTargets(CMakeProjectNode *rootNode, const QList<CMakeBu
buildKeyToNode.insert(buildKey, folderNode); buildKeyToNode.insert(buildKey, folderNode);
}); });
for (const CMakeBuildTarget &t : targets) { for (const CMakeBuildTarget &t : targets) {
if (cancelFuture.isCanceled())
return;
FolderNode *folderNode = buildKeyToNode.value(t.title); FolderNode *folderNode = buildKeyToNode.value(t.title);
if (folderNode) { if (folderNode) {
QSet<std::pair<FilePath, int>> locations; QSet<std::pair<FilePath, int>> locations;
@@ -811,33 +858,43 @@ using namespace FileApiDetails;
// extractData: // extractData:
// -------------------------------------------------------------------- // --------------------------------------------------------------------
FileApiQtcData extractData(FileApiData &input, FileApiQtcData extractData(const QFuture<void> &cancelFuture, FileApiData &input,
const FilePath &sourceDirectory, const Utils::FilePath &sourceDir, const Utils::FilePath &buildDir)
const FilePath &buildDirectory)
{ {
FileApiQtcData result; FileApiQtcData result;
// Preprocess our input: // Preprocess our input:
PreprocessedData data = preprocess(input, sourceDirectory, buildDirectory, result.errorMessage); PreprocessedData data = preprocess(cancelFuture, input, sourceDir, buildDir);
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is if (cancelFuture.isCanceled())
if (!result.errorMessage.isEmpty()) { return {};
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
if (!result.errorMessage.isEmpty())
return {}; return {};
}
// Ninja generator from CMake version 3.20.5 has libraries relative to build directory // Ninja generator from CMake version 3.20.5 has libraries relative to build directory
const bool haveLibrariesRelativeToBuildDirectory = const bool haveLibrariesRelativeToBuildDirectory =
input.replyFile.generator.startsWith("Ninja") input.replyFile.generator.startsWith("Ninja")
&& input.replyFile.cmakeVersion >= QVersionNumber(3, 20, 5); && input.replyFile.cmakeVersion >= QVersionNumber(3, 20, 5);
result.buildTargets = generateBuildTargets(data, sourceDirectory, buildDirectory, haveLibrariesRelativeToBuildDirectory); result.buildTargets = generateBuildTargets(cancelFuture, data, sourceDir, buildDir,
haveLibrariesRelativeToBuildDirectory);
if (cancelFuture.isCanceled())
return {};
result.cmakeFiles = std::move(data.cmakeFiles); result.cmakeFiles = std::move(data.cmakeFiles);
result.projectParts = generateRawProjectParts(data, sourceDirectory, buildDirectory); result.projectParts = generateRawProjectParts(cancelFuture, data, sourceDir, buildDir);
if (cancelFuture.isCanceled())
return {};
auto rootProjectNode = generateRootProjectNode(data, sourceDirectory, buildDirectory); auto rootProjectNode = generateRootProjectNode(cancelFuture, data, sourceDir, buildDir);
if (cancelFuture.isCanceled())
return {};
ProjectTree::applyTreeManager(rootProjectNode.get(), ProjectTree::AsyncPhase); // QRC nodes ProjectTree::applyTreeManager(rootProjectNode.get(), ProjectTree::AsyncPhase); // QRC nodes
result.rootProjectNode = std::move(rootProjectNode); result.rootProjectNode = std::move(rootProjectNode);
setupLocationInfoForTargets(result.rootProjectNode.get(), result.buildTargets); setupLocationInfoForTargets(cancelFuture, result.rootProjectNode.get(), result.buildTargets);
if (cancelFuture.isCanceled())
return {};
result.ctestPath = input.replyFile.ctestExecutable; result.ctestPath = input.replyFile.ctestExecutable;
result.isMultiConfig = input.replyFile.isMultiConfig; result.isMultiConfig = input.replyFile.isMultiConfig;

View File

@@ -52,8 +52,7 @@ public:
bool usesAllCapsTargets = false; bool usesAllCapsTargets = false;
}; };
FileApiQtcData extractData(FileApiData &data, FileApiQtcData extractData(const QFuture<void> &cancelFuture, FileApiData &input,
const Utils::FilePath &sourceDirectory, const Utils::FilePath &sourceDir, const Utils::FilePath &buildDir);
const Utils::FilePath &buildDirectory);
} // CMakeProjectManager::Internal } // CMakeProjectManager::Internal

View File

@@ -252,7 +252,8 @@ void FileApiReader::endState(const FilePath &replyFilePath, bool restoredFromBac
const FilePath sourceDirectory = m_parameters.sourceDirectory; const FilePath sourceDirectory = m_parameters.sourceDirectory;
const FilePath buildDirectory = m_parameters.buildDirectory; const FilePath buildDirectory = m_parameters.buildDirectory;
const QString cmakeBuildType = m_parameters.cmakeBuildType == "Build" ? "" : m_parameters.cmakeBuildType; const QString cmakeBuildType = m_parameters.cmakeBuildType == "Build"
? "" : m_parameters.cmakeBuildType;
m_lastReplyTimestamp = replyFilePath.lastModified(); m_lastReplyTimestamp = replyFilePath.lastModified();
@@ -264,10 +265,12 @@ void FileApiReader::endState(const FilePath &replyFilePath, bool restoredFromBac
replyFilePath, replyFilePath,
cmakeBuildType, cmakeBuildType,
result->errorMessage); result->errorMessage);
if (result->errorMessage.isEmpty()) if (result->errorMessage.isEmpty()) {
*result = extractData(data, sourceDirectory, buildDirectory); *result = extractData(QFuture<void>(promise.future()), data,
else sourceDirectory, buildDirectory);
} else {
qWarning() << result->errorMessage; qWarning() << result->errorMessage;
}
promise.addResult(result); promise.addResult(result);
}); });