forked from qt-creator/qt-creator
CppEditor: Use Utils::SynchronizedValue for project data
Change-Id: I67c07c2f5f5f7e8bb6b10d4f492ad062f82977be Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
#include <utils/process.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/savefile.h>
|
||||
#include <utils/synchronizedvalue.h>
|
||||
#include <utils/temporarydirectory.h>
|
||||
|
||||
#include <QAction>
|
||||
@@ -169,16 +170,20 @@ public:
|
||||
Snapshot m_snapshot;
|
||||
|
||||
// Project integration
|
||||
QReadWriteLock m_projectLock;
|
||||
struct SyncedProjectData
|
||||
{
|
||||
QHash<Project *, ProjectData> m_projectData;
|
||||
QMap<FilePath, QList<ProjectPart::ConstPtr>> m_fileToProjectParts;
|
||||
QMap<QString, ProjectPart::ConstPtr> m_projectPartIdToProjectProjectPart;
|
||||
|
||||
// The members below are cached/(re)calculated from the projects and/or their project parts
|
||||
bool m_dirty;
|
||||
bool m_dirty{true};
|
||||
FilePaths m_projectFiles;
|
||||
HeaderPaths m_headerPaths;
|
||||
Macros m_definedMacros;
|
||||
};
|
||||
|
||||
Utils::SynchronizedValue<SyncedProjectData> m_lockedProjectData;
|
||||
|
||||
// Editor integration
|
||||
mutable QMutex m_cppEditorDocumentsMutex;
|
||||
@@ -215,6 +220,12 @@ public:
|
||||
std::unique_ptr<ILocatorFilter> m_currentDocumentFilter;
|
||||
|
||||
QList<Document::DiagnosticMessage> m_diagnosticMessages;
|
||||
|
||||
static void recalculateProjectPartMappings(SyncedProjectData &ld);
|
||||
static void ensureUpdated(SyncedProjectData &ld);
|
||||
static Utils::FilePaths internalProjectFiles(SyncedProjectData &ld);
|
||||
static ProjectExplorer::HeaderPaths internalHeaderPaths(SyncedProjectData &ld);
|
||||
static ProjectExplorer::Macros internalDefinedMacros(SyncedProjectData &ld);
|
||||
};
|
||||
|
||||
static CppModelManagerPrivate *d;
|
||||
@@ -989,8 +1000,6 @@ CppModelManager::CppModelManager()
|
||||
d->m_findReferences = new CppFindReferences(this);
|
||||
d->m_indexerEnabled = qtcEnvironmentVariable("QTC_NO_CODE_INDEXER") != "1";
|
||||
|
||||
d->m_dirty = true;
|
||||
|
||||
d->m_delayedGcTimer.setObjectName(QLatin1String("CppModelManager::m_delayedGcTimer"));
|
||||
d->m_delayedGcTimer.setSingleShot(true);
|
||||
connect(&d->m_delayedGcTimer, &QTimer::timeout, this, &CppModelManager::GC);
|
||||
@@ -1071,22 +1080,21 @@ bool CppModelManager::replaceDocument(Document::Ptr newDoc)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Make sure that m_projectLock is locked for writing when calling this.
|
||||
void CppModelManager::ensureUpdated()
|
||||
void CppModelManagerPrivate::ensureUpdated(SyncedProjectData &ld)
|
||||
{
|
||||
if (!d->m_dirty)
|
||||
if (!ld.m_dirty)
|
||||
return;
|
||||
|
||||
d->m_projectFiles = internalProjectFiles();
|
||||
d->m_headerPaths = internalHeaderPaths();
|
||||
d->m_definedMacros = internalDefinedMacros();
|
||||
d->m_dirty = false;
|
||||
ld.m_projectFiles = internalProjectFiles(ld);
|
||||
ld.m_headerPaths = internalHeaderPaths(ld);
|
||||
ld.m_definedMacros = internalDefinedMacros(ld);
|
||||
ld.m_dirty = false;
|
||||
}
|
||||
|
||||
FilePaths CppModelManager::internalProjectFiles()
|
||||
FilePaths CppModelManagerPrivate::internalProjectFiles(SyncedProjectData &ld)
|
||||
{
|
||||
FilePaths files;
|
||||
for (const ProjectData &projectData : std::as_const(d->m_projectData)) {
|
||||
for (const ProjectData &projectData : std::as_const(ld.m_projectData)) {
|
||||
for (const ProjectPart::ConstPtr &part : projectData.projectInfo->projectParts()) {
|
||||
for (const ProjectFile &file : part->files)
|
||||
files += file.path;
|
||||
@@ -1096,10 +1104,10 @@ FilePaths CppModelManager::internalProjectFiles()
|
||||
return files;
|
||||
}
|
||||
|
||||
HeaderPaths CppModelManager::internalHeaderPaths()
|
||||
HeaderPaths CppModelManagerPrivate::internalHeaderPaths(SyncedProjectData &ld)
|
||||
{
|
||||
HeaderPaths headerPaths;
|
||||
for (const ProjectData &projectData: std::as_const(d->m_projectData)) {
|
||||
for (const ProjectData &projectData : std::as_const(ld.m_projectData)) {
|
||||
for (const ProjectPart::ConstPtr &part : projectData.projectInfo->projectParts()) {
|
||||
for (const HeaderPath &path : part->headerPaths) {
|
||||
HeaderPath hp(QDir::cleanPath(path.path), path.type);
|
||||
@@ -1120,11 +1128,11 @@ static void addUnique(const Macros &newMacros, Macros ¯os,
|
||||
}
|
||||
}
|
||||
|
||||
Macros CppModelManager::internalDefinedMacros()
|
||||
Macros CppModelManagerPrivate::internalDefinedMacros(SyncedProjectData &ld)
|
||||
{
|
||||
Macros macros;
|
||||
QSet<ProjectExplorer::Macro> alreadyIn;
|
||||
for (const ProjectData &projectData : std::as_const(d->m_projectData)) {
|
||||
for (const ProjectData &projectData : std::as_const(ld.m_projectData)) {
|
||||
for (const ProjectPart::ConstPtr &part : projectData.projectInfo->projectParts()) {
|
||||
addUnique(part->toolChainMacros, macros, alreadyIn);
|
||||
addUnique(part->projectMacros, macros, alreadyIn);
|
||||
@@ -1351,15 +1359,19 @@ QFuture<void> CppModelManager::updateSourceFiles(const QSet<FilePath> &sourceFil
|
||||
|
||||
ProjectInfoList CppModelManager::projectInfos()
|
||||
{
|
||||
QReadLocker locker(&d->m_projectLock);
|
||||
return Utils::transform<QList<ProjectInfo::ConstPtr>>(d->m_projectData,
|
||||
[](const ProjectData &d) { return d.projectInfo; });
|
||||
return Utils::transform<QList<ProjectInfo::ConstPtr>>(d->m_lockedProjectData.readLocked()
|
||||
->m_projectData,
|
||||
[](const ProjectData &d) {
|
||||
return d.projectInfo;
|
||||
});
|
||||
}
|
||||
|
||||
ProjectInfo::ConstPtr CppModelManager::projectInfo(Project *project)
|
||||
{
|
||||
QReadLocker locker(&d->m_projectLock);
|
||||
return d->m_projectData.value(project).projectInfo;
|
||||
return d->m_lockedProjectData.get<ProjectInfo::ConstPtr>(
|
||||
[project](const CppModelManagerPrivate::SyncedProjectData &ld) {
|
||||
return ld.m_projectData.value(project).projectInfo;
|
||||
});
|
||||
}
|
||||
|
||||
/// \brief Remove all files and their includes (recursively) of given ProjectInfo from the snapshot.
|
||||
@@ -1460,18 +1472,17 @@ private:
|
||||
const QSet<FilePath> m_newSourceFiles;
|
||||
};
|
||||
|
||||
/// Make sure that m_projectLock is locked for writing when calling this.
|
||||
void CppModelManager::recalculateProjectPartMappings()
|
||||
void CppModelManagerPrivate::recalculateProjectPartMappings(SyncedProjectData &ld)
|
||||
{
|
||||
d->m_projectPartIdToProjectProjectPart.clear();
|
||||
d->m_fileToProjectParts.clear();
|
||||
for (const ProjectData &projectData : std::as_const(d->m_projectData)) {
|
||||
ld.m_projectPartIdToProjectProjectPart.clear();
|
||||
ld.m_fileToProjectParts.clear();
|
||||
for (const ProjectData &projectData : std::as_const(ld.m_projectData)) {
|
||||
for (const ProjectPart::ConstPtr &projectPart : projectData.projectInfo->projectParts()) {
|
||||
d->m_projectPartIdToProjectProjectPart[projectPart->id()] = projectPart;
|
||||
ld.m_projectPartIdToProjectProjectPart[projectPart->id()] = projectPart;
|
||||
for (const ProjectFile &cxxFile : projectPart->files) {
|
||||
d->m_fileToProjectParts[cxxFile.path].append(projectPart);
|
||||
ld.m_fileToProjectParts[cxxFile.path].append(projectPart);
|
||||
if (FilePath canonical = cxxFile.path.canonicalPath(); canonical != cxxFile.path)
|
||||
d->m_fileToProjectParts[canonical].append(projectPart);
|
||||
ld.m_fileToProjectParts[canonical].append(projectPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1483,12 +1494,15 @@ void CppModelManagerPrivate::setupWatcher(const QFuture<void> &future, Project *
|
||||
ProjectData *projectData, CppModelManager *q)
|
||||
{
|
||||
projectData->indexer = new QFutureWatcher<void>(q);
|
||||
const auto handleFinished = [this, project, watcher = projectData->indexer, q] {
|
||||
if (const auto it = m_projectData.find(project);
|
||||
it != m_projectData.end() && it->indexer == watcher) {
|
||||
const auto handleFinished = [project, watcher = projectData->indexer, q] {
|
||||
d->m_lockedProjectData.write([watcher, project](auto &ld) {
|
||||
const auto it = ld.m_projectData.find(project);
|
||||
if (it != ld.m_projectData.end() && it->indexer == watcher) {
|
||||
it->indexer = nullptr;
|
||||
it->fullyIndexed = !watcher->isCanceled();
|
||||
}
|
||||
});
|
||||
|
||||
watcher->disconnect(q);
|
||||
watcher->deleteLater();
|
||||
};
|
||||
@@ -1542,17 +1556,21 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo::ConstPtr &ne
|
||||
return {};
|
||||
|
||||
ProjectData *projectData = nullptr;
|
||||
{ // Only hold the lock for a limited scope, so the dumping afterwards does not deadlock.
|
||||
QWriteLocker projectLocker(&d->m_projectLock);
|
||||
|
||||
d->m_lockedProjectData.write([&newProjectInfo,
|
||||
project,
|
||||
&filesToReindex,
|
||||
&removedProjectParts,
|
||||
&filesRemoved,
|
||||
&projectData](auto &ld) {
|
||||
const QSet<FilePath> newSourceFiles = newProjectInfo->sourceFiles();
|
||||
|
||||
// Check if we can avoid a full reindexing
|
||||
const auto it = d->m_projectData.find(project);
|
||||
if (it != d->m_projectData.end() && it->projectInfo && it->fullyIndexed) {
|
||||
const auto it = ld.m_projectData.find(project);
|
||||
if (it != ld.m_projectData.end() && it->projectInfo && it->fullyIndexed) {
|
||||
ProjectInfoComparer comparer(*it->projectInfo, *newProjectInfo);
|
||||
if (comparer.configurationOrFilesChanged()) {
|
||||
d->m_dirty = true;
|
||||
ld.m_dirty = true;
|
||||
|
||||
// If the project configuration changed, do a full reindexing
|
||||
if (comparer.configurationChanged()) {
|
||||
@@ -1587,22 +1605,22 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo::ConstPtr &ne
|
||||
|
||||
// A new project was opened/created, do a full indexing
|
||||
} else {
|
||||
d->m_dirty = true;
|
||||
ld.m_dirty = true;
|
||||
filesToReindex.unite(newSourceFiles);
|
||||
}
|
||||
|
||||
// Update Project/ProjectInfo and File/ProjectPart table
|
||||
if (it != d->m_projectData.end()) {
|
||||
if (it != ld.m_projectData.end()) {
|
||||
if (it->indexer)
|
||||
it->indexer->cancel();
|
||||
it->projectInfo = newProjectInfo;
|
||||
it->fullyIndexed = false;
|
||||
}
|
||||
projectData = it == d->m_projectData.end()
|
||||
? &(d->m_projectData[project] = ProjectData{newProjectInfo, nullptr, false})
|
||||
projectData = it == ld.m_projectData.end() ? &(
|
||||
ld.m_projectData[project] = ProjectData{newProjectInfo, nullptr, false})
|
||||
: &(*it);
|
||||
recalculateProjectPartMappings();
|
||||
} // Locker scope
|
||||
CppModelManagerPrivate::recalculateProjectPartMappings(ld);
|
||||
});
|
||||
|
||||
// If requested, dump everything we got
|
||||
if (DumpProjectInfo)
|
||||
@@ -1639,25 +1657,38 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo::ConstPtr &ne
|
||||
|
||||
ProjectPart::ConstPtr CppModelManager::projectPartForId(const QString &projectPartId)
|
||||
{
|
||||
QReadLocker locker(&d->m_projectLock);
|
||||
return d->m_projectPartIdToProjectProjectPart.value(projectPartId);
|
||||
return d->m_lockedProjectData.get<ProjectPart::ConstPtr>(
|
||||
[projectPartId](const CppModelManagerPrivate::SyncedProjectData &ld) {
|
||||
return ld.m_projectPartIdToProjectProjectPart.value(projectPartId);
|
||||
});
|
||||
}
|
||||
|
||||
QList<ProjectPart::ConstPtr> CppModelManager::projectPart(const FilePath &fileName)
|
||||
{
|
||||
{
|
||||
QReadLocker locker(&d->m_projectLock);
|
||||
auto it = d->m_fileToProjectParts.constFind(fileName);
|
||||
if (it != d->m_fileToProjectParts.constEnd())
|
||||
return it.value();
|
||||
}
|
||||
std::optional<QList<ProjectPart::ConstPtr>> result;
|
||||
|
||||
d->m_lockedProjectData.read(
|
||||
[&fileName, &result](const CppModelManagerPrivate::SyncedProjectData &sd) {
|
||||
const auto it = sd.m_fileToProjectParts.constFind(fileName);
|
||||
if (it != sd.m_fileToProjectParts.constEnd())
|
||||
result = *it;
|
||||
});
|
||||
|
||||
if (result)
|
||||
return *result;
|
||||
|
||||
const FilePath canonicalPath = fileName.canonicalPath();
|
||||
QWriteLocker locker(&d->m_projectLock);
|
||||
const auto it = d->m_fileToProjectParts.constFind(canonicalPath);
|
||||
if (it == d->m_fileToProjectParts.constEnd())
|
||||
return {};
|
||||
d->m_fileToProjectParts.insert(fileName, it.value());
|
||||
return it.value();
|
||||
|
||||
d->m_lockedProjectData.write(
|
||||
[&fileName, &canonicalPath, &result](CppModelManagerPrivate::SyncedProjectData &sd) {
|
||||
const auto it = sd.m_fileToProjectParts.constFind(canonicalPath);
|
||||
if (it == sd.m_fileToProjectParts.constEnd())
|
||||
return;
|
||||
sd.m_fileToProjectParts.insert(fileName, it.value());
|
||||
result = it.value();
|
||||
});
|
||||
|
||||
return result.value_or(QList<ProjectPart::ConstPtr>{});
|
||||
}
|
||||
|
||||
QList<ProjectPart::ConstPtr> CppModelManager::projectPartFromDependencies(
|
||||
@@ -1713,8 +1744,7 @@ void CppModelManager::emitAbstractEditorSupportRemoved(const QString &filePath)
|
||||
|
||||
void CppModelManager::onProjectAdded(Project *)
|
||||
{
|
||||
QWriteLocker locker(&d->m_projectLock);
|
||||
d->m_dirty = true;
|
||||
d->m_lockedProjectData.writeLocked()->m_dirty = true;
|
||||
}
|
||||
|
||||
void CppModelManager::delayedGC()
|
||||
@@ -1735,17 +1765,17 @@ void CppModelManager::onAboutToRemoveProject(Project *project)
|
||||
{
|
||||
QStringList idsOfRemovedProjectParts;
|
||||
|
||||
{
|
||||
QWriteLocker locker(&d->m_projectLock);
|
||||
d->m_dirty = true;
|
||||
const QStringList projectPartsIdsBefore = d->m_projectPartIdToProjectProjectPart.keys();
|
||||
d->m_lockedProjectData.write([project, &idsOfRemovedProjectParts](
|
||||
CppModelManagerPrivate::SyncedProjectData &sd) {
|
||||
sd.m_dirty = true;
|
||||
const QStringList projectPartsIdsBefore = sd.m_projectPartIdToProjectProjectPart.keys();
|
||||
|
||||
d->m_projectData.remove(project);
|
||||
recalculateProjectPartMappings();
|
||||
sd.m_projectData.remove(project);
|
||||
CppModelManagerPrivate::recalculateProjectPartMappings(sd);
|
||||
|
||||
const QStringList projectPartsIdsAfter = d->m_projectPartIdToProjectProjectPart.keys();
|
||||
const QStringList projectPartsIdsAfter = sd.m_projectPartIdToProjectProjectPart.keys();
|
||||
idsOfRemovedProjectParts = removedProjectParts(projectPartsIdsBefore, projectPartsIdsAfter);
|
||||
}
|
||||
});
|
||||
|
||||
if (!idsOfRemovedProjectParts.isEmpty())
|
||||
emit m_instance->projectPartsRemoved(idsOfRemovedProjectParts);
|
||||
@@ -1758,11 +1788,8 @@ void CppModelManager::onActiveProjectChanged(Project *project)
|
||||
if (!project)
|
||||
return; // Last project closed.
|
||||
|
||||
{
|
||||
QReadLocker locker(&d->m_projectLock);
|
||||
if (!d->m_projectData.contains(project))
|
||||
if (!d->m_lockedProjectData.readLocked()->m_projectData.contains(project))
|
||||
return; // Not yet known to us.
|
||||
}
|
||||
|
||||
updateCppEditorDocuments();
|
||||
}
|
||||
@@ -2103,32 +2130,33 @@ CppIndexingSupport *CppModelManager::indexingSupport()
|
||||
|
||||
FilePaths CppModelManager::projectFiles()
|
||||
{
|
||||
QWriteLocker locker(&d->m_projectLock);
|
||||
ensureUpdated();
|
||||
|
||||
return d->m_projectFiles;
|
||||
return d->m_lockedProjectData.update<FilePaths>(
|
||||
[](CppModelManagerPrivate::SyncedProjectData &sd) {
|
||||
CppModelManagerPrivate::ensureUpdated(sd);
|
||||
return sd.m_projectFiles;
|
||||
});
|
||||
}
|
||||
|
||||
HeaderPaths CppModelManager::headerPaths()
|
||||
{
|
||||
QWriteLocker locker(&d->m_projectLock);
|
||||
ensureUpdated();
|
||||
|
||||
return d->m_headerPaths;
|
||||
return d->m_lockedProjectData.update<HeaderPaths>(
|
||||
[](CppModelManagerPrivate::SyncedProjectData &sd) {
|
||||
CppModelManagerPrivate::ensureUpdated(sd);
|
||||
return sd.m_headerPaths;
|
||||
});
|
||||
}
|
||||
|
||||
void CppModelManager::setHeaderPaths(const HeaderPaths &headerPaths)
|
||||
{
|
||||
QWriteLocker locker(&d->m_projectLock);
|
||||
d->m_headerPaths = headerPaths;
|
||||
d->m_lockedProjectData.writeLocked()->m_headerPaths = headerPaths;
|
||||
}
|
||||
|
||||
Macros CppModelManager::definedMacros()
|
||||
{
|
||||
QWriteLocker locker(&d->m_projectLock);
|
||||
ensureUpdated();
|
||||
|
||||
return d->m_definedMacros;
|
||||
return d->m_lockedProjectData.update<Macros>([](CppModelManagerPrivate::SyncedProjectData &sd) {
|
||||
CppModelManagerPrivate::ensureUpdated(sd);
|
||||
return sd.m_definedMacros;
|
||||
});
|
||||
}
|
||||
|
||||
void CppModelManager::enableGarbageCollector(bool enable)
|
||||
|
@@ -290,7 +290,6 @@ private:
|
||||
static void setupFallbackProjectPart();
|
||||
|
||||
static void delayedGC();
|
||||
static void recalculateProjectPartMappings();
|
||||
|
||||
static void replaceSnapshot(const CPlusPlus::Snapshot &newSnapshot);
|
||||
static void removeFilesFromSnapshot(const QSet<Utils::FilePath> &removedFiles);
|
||||
@@ -298,11 +297,6 @@ private:
|
||||
|
||||
static WorkingCopy buildWorkingCopyList();
|
||||
|
||||
static void ensureUpdated();
|
||||
static Utils::FilePaths internalProjectFiles();
|
||||
static ProjectExplorer::HeaderPaths internalHeaderPaths();
|
||||
static ProjectExplorer::Macros internalDefinedMacros();
|
||||
|
||||
static void dumpModelManagerConfiguration(const QString &logFileId);
|
||||
static void initCppTools();
|
||||
};
|
||||
|
Reference in New Issue
Block a user