QmakeProjectManager: Restore incremental re-parsing

This was broken in commit 37aecdd112, where we overlooked that a special
type of IDocument was used that triggers a re-parse of only the affected
part of the project tree. As a result, all changes to a .pri or .pro file
would trigger a re-parse of the entire project.

Fixes: QTCREATORBUG-24572
Change-Id: I480cff4e53cf86a17e1eaac0eb9b32901bc87051
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Christian Kandeler
2020-09-10 10:39:56 +02:00
parent a50f1baf5d
commit f3bd07efd1
4 changed files with 73 additions and 42 deletions

View File

@@ -64,7 +64,6 @@
#include <QFileDialog> #include <QFileDialog>
#include <limits> #include <limits>
#include <memory>
/*! /*!
\class ProjectExplorer::Project \class ProjectExplorer::Project
@@ -357,7 +356,8 @@ void Project::setNeedsInitialExpansion(bool needsExpansion)
d->m_needsInitialExpansion = needsExpansion; d->m_needsInitialExpansion = needsExpansion;
} }
void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths) void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths,
const DocGenerator docGenerator)
{ {
QSet<Utils::FilePath> uniqueNewFiles = projectDocumentPaths; QSet<Utils::FilePath> uniqueNewFiles = projectDocumentPaths;
uniqueNewFiles.remove(projectFilePath()); // Make sure to never add the main project file! uniqueNewFiles.remove(projectFilePath()); // Make sure to never add the main project file!
@@ -372,8 +372,14 @@ void Project::setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentP
return toRemove.contains(d->filePath()); return toRemove.contains(d->filePath());
}); });
for (const Utils::FilePath &p : toAdd) { for (const Utils::FilePath &p : toAdd) {
d->m_extraProjectDocuments.emplace_back( if (docGenerator) {
std::make_unique<ProjectDocument>(d->m_document->mimeType(), p, this)); std::unique_ptr<Core::IDocument> doc = docGenerator(p);
QTC_ASSERT(doc, continue);
d->m_extraProjectDocuments.push_back(std::move(doc));
} else {
d->m_extraProjectDocuments.emplace_back(std::make_unique<ProjectDocument>(
d->m_document->mimeType(), p, this));
}
} }
} }
@@ -802,6 +808,19 @@ bool Project::isKnownFile(const Utils::FilePath &filename) const
&element, nodeLessThan); &element, nodeLessThan);
} }
const Node *Project::nodeForFilePath(const Utils::FilePath &filePath,
const Project::NodeMatcher &extraMatcher)
{
const FileNode dummy(filePath, FileType::Unknown);
const auto range = std::equal_range(d->m_sortedNodeList.cbegin(), d->m_sortedNodeList.cend(),
&dummy, &nodeLessThan);
for (auto it = range.first; it != range.second; ++it) {
if ((*it)->filePath() == filePath && (!extraMatcher || extraMatcher(*it)))
return *it;
}
return nullptr;
}
void Project::setProjectLanguages(Core::Context language) void Project::setProjectLanguages(Core::Context language)
{ {
if (d->m_projectLanguages == language) if (d->m_projectLanguages == language)

View File

@@ -39,6 +39,7 @@
#include <QFileSystemModel> #include <QFileSystemModel>
#include <functional> #include <functional>
#include <memory>
namespace Core { class Context; } namespace Core { class Context; }
namespace Utils { namespace Utils {
@@ -123,6 +124,8 @@ public:
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;
const Node *nodeForFilePath(const Utils::FilePath &filePath,
const NodeMatcher &extraMatcher = {});
virtual QVariantMap toMap() const; virtual QVariantMap toMap() const;
@@ -159,9 +162,11 @@ public:
void setRootProjectNode(std::unique_ptr<ProjectNode> &&root); void setRootProjectNode(std::unique_ptr<ProjectNode> &&root);
// Set project files that will be watched and trigger the same callback // Set project files that will be watched and by default trigger the same callback
// as the main project file. // as the main project file.
void setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths); using DocGenerator = std::function<std::unique_ptr<Core::IDocument>(const Utils::FilePath &)>;
void setExtraProjectFiles(const QSet<Utils::FilePath> &projectDocumentPaths,
const DocGenerator docGenerator = {});
void setDisplayName(const QString &name); void setDisplayName(const QString &name);
void setProjectLanguage(Utils::Id id, bool enabled); void setProjectLanguage(Utils::Id id, bool enabled);

View File

@@ -63,41 +63,6 @@ using namespace QmakeProjectManager::Internal;
using namespace QMakeInternal; using namespace QMakeInternal;
using namespace Utils; using namespace Utils;
namespace {
class QmakePriFileDocument : public Core::IDocument
{
public:
QmakePriFileDocument(QmakePriFile *qmakePriFile, const Utils::FilePath &filePath) :
IDocument(nullptr), m_priFile(qmakePriFile)
{
setId("Qmake.PriFile");
setMimeType(QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE));
setFilePath(filePath);
}
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override
{
Q_UNUSED(state)
Q_UNUSED(type)
return BehaviorSilent;
}
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override
{
Q_UNUSED(errorString)
Q_UNUSED(flag)
if (type == TypePermissions)
return true;
m_priFile->scheduleUpdate();
return true;
}
private:
QmakePriFile *m_priFile;
};
} // namespace
namespace QmakeProjectManager { namespace QmakeProjectManager {
static Q_LOGGING_CATEGORY(qmakeParse, "qtc.qmake.parsing", QtWarningMsg); static Q_LOGGING_CATEGORY(qmakeParse, "qtc.qmake.parsing", QtWarningMsg);

View File

@@ -33,6 +33,7 @@
#include "qmakeprojectmanagerconstants.h" #include "qmakeprojectmanagerconstants.h"
#include "qmakestep.h" #include "qmakestep.h"
#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/icontext.h> #include <coreplugin/icontext.h>
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -98,6 +99,38 @@ static Q_LOGGING_CATEGORY(qmakeBuildSystemLog, "qtc.qmake.buildsystem", QtWarnin
<< msg; \ << msg; \
} }
class QmakePriFileDocument : public Core::IDocument
{
public:
QmakePriFileDocument(QmakePriFile *qmakePriFile, const Utils::FilePath &filePath) :
IDocument(nullptr), m_priFile(qmakePriFile)
{
setId("Qmake.PriFile");
setMimeType(QLatin1String(QmakeProjectManager::Constants::PROFILE_MIMETYPE));
setFilePath(filePath);
Core::DocumentManager::addDocument(this);
}
ReloadBehavior reloadBehavior(ChangeTrigger state, ChangeType type) const override
{
Q_UNUSED(state)
Q_UNUSED(type)
return BehaviorSilent;
}
bool reload(QString *errorString, ReloadFlag flag, ChangeType type) override
{
Q_UNUSED(errorString)
Q_UNUSED(flag)
if (type == TypePermissions)
return true;
m_priFile->scheduleUpdate();
return true;
}
private:
QmakePriFile *m_priFile;
};
/// Watches folders for QmakePriFile nodes /// Watches folders for QmakePriFile nodes
/// use one file system watcher to watch all folders /// use one file system watcher to watch all folders
/// such minimizing system ressouce usage /// such minimizing system ressouce usage
@@ -270,8 +303,17 @@ void QmakeBuildSystem::updateDocuments()
QSet<FilePath> projectDocuments; QSet<FilePath> projectDocuments;
project()->rootProjectNode()->forEachProjectNode([&projectDocuments](const ProjectNode *n) { project()->rootProjectNode()->forEachProjectNode([&projectDocuments](const ProjectNode *n) {
projectDocuments.insert(n->filePath()); projectDocuments.insert(n->filePath());
});
project()->setExtraProjectFiles(projectDocuments, [p = project()](const FilePath &fp)
-> std::unique_ptr<Core::IDocument> {
const Node * const n = p->nodeForFilePath(fp, [](const Node *n) {
return dynamic_cast<const QmakePriFileNode *>(n); });
QTC_ASSERT(n, return std::make_unique<Core::IDocument>());
QmakePriFile * const priFile = static_cast<const QmakePriFileNode *>(n)->priFile();
QTC_ASSERT(priFile, return std::make_unique<Core::IDocument>());
return std::make_unique<QmakePriFileDocument>(priFile, fp);
}); });
project()->setExtraProjectFiles(projectDocuments);
} }
void QmakeBuildSystem::updateCppCodeModel() void QmakeBuildSystem::updateCppCodeModel()