forked from qt-creator/qt-creator
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:
@@ -12,10 +12,10 @@
|
||||
#include <cppeditor/cppeditorconstants.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/icon.h>
|
||||
#include <utils/mimeutils.h>
|
||||
#include <utils/process.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/icon.h>
|
||||
|
||||
#include <projectexplorer/projecttree.h>
|
||||
|
||||
@@ -45,14 +45,13 @@ public:
|
||||
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 &buildDirectory)
|
||||
{
|
||||
CMakeFileResult result;
|
||||
|
||||
if (cmakefiles.empty())
|
||||
return result;
|
||||
return {};
|
||||
|
||||
// Uniquify fileInfos
|
||||
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
|
||||
// reading many small files, which can get slow especially on remote devices.
|
||||
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);
|
||||
CMakeFileInfo absolute(info);
|
||||
absolute.path = sfn;
|
||||
@@ -86,7 +87,15 @@ CMakeFileResult extractCMakeFilesData(const std::vector<CMakeFileInfo> &cmakefil
|
||||
|
||||
mapResult.waitForFinished();
|
||||
|
||||
if (cancelFuture.isCanceled())
|
||||
return {};
|
||||
|
||||
CMakeFileResult result;
|
||||
|
||||
for (const auto &info : mapResult.results()) {
|
||||
if (cancelFuture.isCanceled())
|
||||
return {};
|
||||
|
||||
result.cmakeFiles.insert(info);
|
||||
|
||||
if (info.isCMake && !info.isCMakeListsDotTxt) {
|
||||
@@ -132,22 +141,17 @@ public:
|
||||
std::vector<TargetDetails> targetDetails;
|
||||
};
|
||||
|
||||
PreprocessedData preprocess(FileApiData &data,
|
||||
const FilePath &sourceDirectory,
|
||||
const FilePath &buildDirectory,
|
||||
QString &errorMessage)
|
||||
static PreprocessedData preprocess(const QFuture<void> &cancelFuture, FileApiData &data,
|
||||
const FilePath &sourceDirectory, const FilePath &buildDirectory)
|
||||
{
|
||||
Q_UNUSED(errorMessage)
|
||||
|
||||
PreprocessedData result;
|
||||
|
||||
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
||||
|
||||
result.codemodel = std::move(data.codemodel);
|
||||
|
||||
CMakeFileResult cmakeFileResult = extractCMakeFilesData(data.cmakeFiles,
|
||||
sourceDirectory,
|
||||
buildDirectory);
|
||||
CMakeFileResult cmakeFileResult = extractCMakeFilesData(cancelFuture, data.cmakeFiles,
|
||||
sourceDirectory, buildDirectory);
|
||||
|
||||
result.cmakeFiles = std::move(cmakeFileResult.cmakeFiles);
|
||||
result.cmakeNodesSource = std::move(cmakeFileResult.cmakeNodesSource);
|
||||
@@ -160,7 +164,8 @@ PreprocessedData preprocess(FileApiData &data,
|
||||
return result;
|
||||
}
|
||||
|
||||
QVector<FolderNode::LocationInfo> extractBacktraceInformation(const BacktraceInfo &backtraces,
|
||||
static QVector<FolderNode::LocationInfo> extractBacktraceInformation(
|
||||
const BacktraceInfo &backtraces,
|
||||
const FilePath &sourceDir,
|
||||
int backtraceIndex,
|
||||
unsigned int locationInfoPriority)
|
||||
@@ -200,14 +205,11 @@ static bool isChildOf(const FilePath &path, const FilePaths &prefixes)
|
||||
return false;
|
||||
}
|
||||
|
||||
QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input,
|
||||
static CMakeBuildTarget toBuildTarget(const TargetDetails &t,
|
||||
const FilePath &sourceDirectory,
|
||||
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);
|
||||
|
||||
CMakeBuildTarget ct;
|
||||
@@ -293,7 +295,7 @@ QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input,
|
||||
if (part.startsWith("-"))
|
||||
continue;
|
||||
|
||||
const FilePath buildDir = haveLibrariesRelativeToBuildDirectory ? buildDirectory : currentBuildDir;
|
||||
const FilePath buildDir = relativeLibs ? buildDirectory : currentBuildDir;
|
||||
FilePath tmp = buildDir.resolvePath(part);
|
||||
|
||||
if (f.role == "libraries")
|
||||
@@ -326,9 +328,22 @@ QList<CMakeBuildTarget> generateBuildTargets(const PreprocessedData &input,
|
||||
}
|
||||
ct.libraryDirectories = filteredUnique(librarySeachPaths);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -341,24 +356,28 @@ static QStringList splitFragments(const QStringList &fragments)
|
||||
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");
|
||||
}
|
||||
|
||||
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"
|
||||
&& path.fileName().startsWith("unity_");
|
||||
}
|
||||
|
||||
RawProjectParts generateRawProjectParts(const PreprocessedData &input,
|
||||
static RawProjectParts generateRawProjectParts(const QFuture<void> &cancelFuture,
|
||||
const PreprocessedData &input,
|
||||
const FilePath &sourceDirectory,
|
||||
const FilePath &buildDirectory)
|
||||
{
|
||||
RawProjectParts rpps;
|
||||
|
||||
for (const TargetDetails &t : input.targetDetails) {
|
||||
if (cancelFuture.isCanceled())
|
||||
return {};
|
||||
|
||||
bool needPostfix = t.compileGroups.size() > 1;
|
||||
int count = 1;
|
||||
for (const CompileInfo &ci : t.compileGroups) {
|
||||
@@ -520,7 +539,9 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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 FilePath &sourceDir)
|
||||
{
|
||||
for (const FileApiDetails::Project &p : config.projects) {
|
||||
if (cancelFuture.isCanceled())
|
||||
return;
|
||||
|
||||
if (p.parent == -1)
|
||||
continue; // Top-level project has already been covered
|
||||
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,
|
||||
FolderNode *targetRoot)
|
||||
{
|
||||
@@ -576,7 +603,7 @@ FolderNode *createSourceGroupNode(const QString &sourceGroupName,
|
||||
return currentNode;
|
||||
}
|
||||
|
||||
void addCompileGroups(ProjectNode *targetRoot,
|
||||
static void addCompileGroups(ProjectNode *targetRoot,
|
||||
const Utils::FilePath &topSourceDirectory,
|
||||
const Utils::FilePath &sourceDirectory,
|
||||
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));
|
||||
}
|
||||
|
||||
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 std::vector<TargetDetails> &targetDetails,
|
||||
const FilePath &sourceDir,
|
||||
@@ -702,6 +730,9 @@ void addTargets(const QHash<Utils::FilePath, ProjectExplorer::ProjectNode *> &cm
|
||||
};
|
||||
|
||||
for (const FileApiDetails::Target &t : config.targets) {
|
||||
if (cancelFuture.isCanceled())
|
||||
return;
|
||||
|
||||
const TargetDetails &td = getTargetDetails(t.id);
|
||||
|
||||
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(
|
||||
PreprocessedData &data, const FilePath &sourceDirectory, const FilePath &buildDirectory)
|
||||
static std::unique_ptr<CMakeProjectNode> generateRootProjectNode(const QFuture<void> &cancelFuture,
|
||||
PreprocessedData &data,
|
||||
const FilePath &sourceDirectory,
|
||||
const FilePath &buildDirectory)
|
||||
{
|
||||
std::unique_ptr<CMakeProjectNode> result = std::make_unique<CMakeProjectNode>(sourceDirectory);
|
||||
|
||||
@@ -733,25 +766,34 @@ std::unique_ptr<CMakeProjectNode> generateRootProjectNode(
|
||||
std::move(data.cmakeListNodes));
|
||||
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.targetDetails,
|
||||
sourceDirectory,
|
||||
buildDirectory);
|
||||
if (cancelFuture.isCanceled())
|
||||
return {};
|
||||
|
||||
if (!data.cmakeNodesSource.empty() || !data.cmakeNodesBuild.empty()
|
||||
|| !data.cmakeNodesOther.empty())
|
||||
|| !data.cmakeNodesOther.empty()) {
|
||||
addCMakeInputs(result.get(),
|
||||
sourceDirectory,
|
||||
buildDirectory,
|
||||
std::move(data.cmakeNodesSource),
|
||||
std::move(data.cmakeNodesBuild),
|
||||
std::move(data.cmakeNodesOther));
|
||||
|
||||
}
|
||||
if (cancelFuture.isCanceled())
|
||||
return {};
|
||||
|
||||
addCMakePresets(result.get(), sourceDirectory);
|
||||
if (cancelFuture.isCanceled())
|
||||
return {};
|
||||
|
||||
data.cmakeNodesSource.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;
|
||||
}
|
||||
|
||||
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);
|
||||
QHash<QString, FolderNode *> buildKeyToNode;
|
||||
@@ -771,6 +815,9 @@ void setupLocationInfoForTargets(CMakeProjectNode *rootNode, const QList<CMakeBu
|
||||
buildKeyToNode.insert(buildKey, folderNode);
|
||||
});
|
||||
for (const CMakeBuildTarget &t : targets) {
|
||||
if (cancelFuture.isCanceled())
|
||||
return;
|
||||
|
||||
FolderNode *folderNode = buildKeyToNode.value(t.title);
|
||||
if (folderNode) {
|
||||
QSet<std::pair<FilePath, int>> locations;
|
||||
@@ -811,33 +858,43 @@ using namespace FileApiDetails;
|
||||
// extractData:
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
FileApiQtcData extractData(FileApiData &input,
|
||||
const FilePath &sourceDirectory,
|
||||
const FilePath &buildDirectory)
|
||||
FileApiQtcData extractData(const QFuture<void> &cancelFuture, FileApiData &input,
|
||||
const Utils::FilePath &sourceDir, const Utils::FilePath &buildDir)
|
||||
{
|
||||
FileApiQtcData result;
|
||||
|
||||
// Preprocess our input:
|
||||
PreprocessedData data = preprocess(input, sourceDirectory, buildDirectory, result.errorMessage);
|
||||
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
||||
if (!result.errorMessage.isEmpty()) {
|
||||
PreprocessedData data = preprocess(cancelFuture, input, sourceDir, buildDir);
|
||||
if (cancelFuture.isCanceled())
|
||||
return {};
|
||||
|
||||
result.cache = std::move(data.cache); // Make sure this is available, even when nothing else is
|
||||
if (!result.errorMessage.isEmpty())
|
||||
return {};
|
||||
}
|
||||
|
||||
// Ninja generator from CMake version 3.20.5 has libraries relative to build directory
|
||||
const bool haveLibrariesRelativeToBuildDirectory =
|
||||
input.replyFile.generator.startsWith("Ninja")
|
||||
&& 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.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
|
||||
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.isMultiConfig = input.replyFile.isMultiConfig;
|
||||
|
||||
@@ -52,8 +52,7 @@ public:
|
||||
bool usesAllCapsTargets = false;
|
||||
};
|
||||
|
||||
FileApiQtcData extractData(FileApiData &data,
|
||||
const Utils::FilePath &sourceDirectory,
|
||||
const Utils::FilePath &buildDirectory);
|
||||
FileApiQtcData extractData(const QFuture<void> &cancelFuture, FileApiData &input,
|
||||
const Utils::FilePath &sourceDir, const Utils::FilePath &buildDir);
|
||||
|
||||
} // CMakeProjectManager::Internal
|
||||
|
||||
@@ -252,7 +252,8 @@ void FileApiReader::endState(const FilePath &replyFilePath, bool restoredFromBac
|
||||
|
||||
const FilePath sourceDirectory = m_parameters.sourceDirectory;
|
||||
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();
|
||||
|
||||
@@ -264,10 +265,12 @@ void FileApiReader::endState(const FilePath &replyFilePath, bool restoredFromBac
|
||||
replyFilePath,
|
||||
cmakeBuildType,
|
||||
result->errorMessage);
|
||||
if (result->errorMessage.isEmpty())
|
||||
*result = extractData(data, sourceDirectory, buildDirectory);
|
||||
else
|
||||
if (result->errorMessage.isEmpty()) {
|
||||
*result = extractData(QFuture<void>(promise.future()), data,
|
||||
sourceDirectory, buildDirectory);
|
||||
} else {
|
||||
qWarning() << result->errorMessage;
|
||||
}
|
||||
|
||||
promise.addResult(result);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user