forked from qt-creator/qt-creator
CppTools: Rework handling of ProjectInfo changes
(a) The code model manager figures out by itself which files were added or removed from the project. If this was done successfully, check also the timestamp of the common files and reindex if necessary. (b) A full reindexing is only triggered if the project configuration changes (defines, includes, framework paths). (c) If project files were removed, the garbage collector is called. Task-number: QTCREATORBUG-9730 Change-Id: Ib855614b070880576233a3525813617c967a72f3 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@digia.com>
This commit is contained in:
@@ -172,12 +172,11 @@ static const char pp_configuration[] =
|
||||
"#define __inline inline\n"
|
||||
"#define __forceinline inline\n";
|
||||
|
||||
void CppModelManager::updateModifiedSourceFiles()
|
||||
QStringList CppModelManager::timeStampModifiedFiles(const QList<Document::Ptr> documentsToCheck)
|
||||
{
|
||||
const Snapshot snapshot = this->snapshot();
|
||||
QStringList sourceFiles;
|
||||
|
||||
foreach (const Document::Ptr doc, snapshot) {
|
||||
foreach (const Document::Ptr doc, documentsToCheck) {
|
||||
const QDateTime lastModified = doc->lastModified();
|
||||
|
||||
if (!lastModified.isNull()) {
|
||||
@@ -188,7 +187,18 @@ void CppModelManager::updateModifiedSourceFiles()
|
||||
}
|
||||
}
|
||||
|
||||
updateSourceFiles(sourceFiles);
|
||||
return sourceFiles;
|
||||
}
|
||||
|
||||
void CppModelManager::updateModifiedSourceFiles()
|
||||
{
|
||||
const Snapshot snapshot = this->snapshot();
|
||||
QList<Document::Ptr> documentsToCheck;
|
||||
foreach (const Document::Ptr document, snapshot)
|
||||
documentsToCheck << document;
|
||||
|
||||
const QStringList filesToUpdate = timeStampModifiedFiles(documentsToCheck);
|
||||
updateSourceFiles(filesToUpdate);
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -584,39 +594,155 @@ CppModelManager::ProjectInfo CppModelManager::projectInfo(ProjectExplorer::Proje
|
||||
return m_projectToProjectsInfo.value(project, ProjectInfo(project));
|
||||
}
|
||||
|
||||
QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &pinfo)
|
||||
/// \brief Remove all files and their includes (recursively) of given ProjectInfo from the snapshot.
|
||||
void CppModelManager::removeProjectInfoFilesAndIncludesFromSnapshot(const ProjectInfo &projectInfo)
|
||||
{
|
||||
if (!pinfo.isValid())
|
||||
if (!projectInfo.isValid())
|
||||
return;
|
||||
|
||||
QMutexLocker snapshotLocker(&m_snapshotMutex);
|
||||
foreach (const ProjectPart::Ptr &projectPart, projectInfo.projectParts()) {
|
||||
foreach (const ProjectFile &cxxFile, projectPart->files) {
|
||||
foreach (const QString &fileName, m_snapshot.allIncludesForDocument(cxxFile.path))
|
||||
m_snapshot.remove(fileName);
|
||||
m_snapshot.remove(cxxFile.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Remove all given files from the snapshot.
|
||||
void CppModelManager::removeFilesFromSnapshot(const QSet<QString> &filesToRemove)
|
||||
{
|
||||
QMutexLocker snapshotLocker(&m_snapshotMutex);
|
||||
QSetIterator<QString> i(filesToRemove);
|
||||
while (i.hasNext())
|
||||
m_snapshot.remove(i.next());
|
||||
}
|
||||
|
||||
class ProjectInfoComparer
|
||||
{
|
||||
public:
|
||||
ProjectInfoComparer(const CppModelManager::ProjectInfo &oldProjectInfo,
|
||||
const CppModelManager::ProjectInfo &newProjectInfo)
|
||||
: m_old(oldProjectInfo)
|
||||
, m_oldSourceFiles(oldProjectInfo.sourceFiles().toSet())
|
||||
, m_new(newProjectInfo)
|
||||
, m_newSourceFiles(newProjectInfo.sourceFiles().toSet())
|
||||
{}
|
||||
|
||||
bool definesChanged() const
|
||||
{
|
||||
return m_new.defines() != m_old.defines();
|
||||
}
|
||||
|
||||
bool configurationChanged() const
|
||||
{
|
||||
return definesChanged()
|
||||
|| m_new.includePaths() != m_old.includePaths()
|
||||
|| m_new.frameworkPaths() != m_old.frameworkPaths();
|
||||
}
|
||||
|
||||
bool nothingChanged() const
|
||||
{
|
||||
return !configurationChanged() && m_new.sourceFiles() == m_old.sourceFiles();
|
||||
}
|
||||
|
||||
QSet<QString> addedFiles() const
|
||||
{
|
||||
QSet<QString> addedFilesSet = m_newSourceFiles;
|
||||
addedFilesSet.subtract(m_oldSourceFiles);
|
||||
return addedFilesSet;
|
||||
}
|
||||
|
||||
QSet<QString> removedFiles() const
|
||||
{
|
||||
QSet<QString> removedFilesSet = m_oldSourceFiles;
|
||||
removedFilesSet.subtract(m_newSourceFiles);
|
||||
return removedFilesSet;
|
||||
}
|
||||
|
||||
/// Returns a list of common files that have a changed timestamp.
|
||||
QSet<QString> timeStampModifiedFiles(const Snapshot &snapshot) const
|
||||
{
|
||||
QSet<QString> commonSourceFiles = m_newSourceFiles;
|
||||
commonSourceFiles.intersect(m_oldSourceFiles);
|
||||
|
||||
QList<Document::Ptr> documentsToCheck;
|
||||
QSetIterator<QString> i(commonSourceFiles);
|
||||
while (i.hasNext()) {
|
||||
const QString file = i.next();
|
||||
if (Document::Ptr document = snapshot.document(file))
|
||||
documentsToCheck << document;
|
||||
}
|
||||
|
||||
return CppModelManager::timeStampModifiedFiles(documentsToCheck).toSet();
|
||||
}
|
||||
|
||||
private:
|
||||
const CppModelManager::ProjectInfo &m_old;
|
||||
const QSet<QString> m_oldSourceFiles;
|
||||
|
||||
const CppModelManager::ProjectInfo &m_new;
|
||||
const QSet<QString> m_newSourceFiles;
|
||||
};
|
||||
|
||||
QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &newProjectInfo)
|
||||
{
|
||||
if (!newProjectInfo.isValid())
|
||||
return QFuture<void>();
|
||||
|
||||
{ // Only hold the mutex for a limited scope, so the dumping afterwards does not deadlock.
|
||||
QMutexLocker locker(&m_projectMutex);
|
||||
QStringList filesToReindex;
|
||||
bool filesRemoved = false;
|
||||
|
||||
ProjectExplorer::Project *project = pinfo.project().data();
|
||||
{ // Only hold the mutex for a limited scope, so the dumping afterwards does not deadlock.
|
||||
QMutexLocker projectLocker(&m_projectMutex);
|
||||
|
||||
ProjectExplorer::Project *project = newProjectInfo.project().data();
|
||||
const QStringList newSourceFiles = newProjectInfo.sourceFiles();
|
||||
|
||||
// Check if we can avoid a full reindexing
|
||||
ProjectInfo oldProjectInfo = m_projectToProjectsInfo.value(project);
|
||||
if (oldProjectInfo.isValid()) {
|
||||
if (pinfo.defines() == oldProjectInfo.defines()
|
||||
&& pinfo.includePaths() == oldProjectInfo.includePaths()
|
||||
&& pinfo.frameworkPaths() == oldProjectInfo.frameworkPaths()
|
||||
&& pinfo.sourceFiles() == oldProjectInfo.sourceFiles()) {
|
||||
ProjectInfoComparer comparer(oldProjectInfo, newProjectInfo);
|
||||
if (comparer.nothingChanged())
|
||||
return QFuture<void>();
|
||||
}
|
||||
|
||||
foreach (const ProjectPart::Ptr &projectPart, oldProjectInfo.projectParts()) {
|
||||
foreach (const ProjectFile &cxxFile, projectPart->files) {
|
||||
foreach (const QString &fileName,
|
||||
m_snapshot.allIncludesForDocument(cxxFile.path)) {
|
||||
m_snapshot.remove(fileName);
|
||||
}
|
||||
m_snapshot.remove(cxxFile.path);
|
||||
// If the project configuration changed, do a full reindexing
|
||||
if (comparer.configurationChanged()) {
|
||||
removeProjectInfoFilesAndIncludesFromSnapshot(oldProjectInfo);
|
||||
filesToReindex << newSourceFiles;
|
||||
|
||||
// The "configuration file" includes all defines and therefore should be updated
|
||||
if (comparer.definesChanged()) {
|
||||
QMutexLocker snapshotLocker(&m_snapshotMutex);
|
||||
m_snapshot.remove(configurationFileName());
|
||||
}
|
||||
|
||||
// Otherwise check for added and modified files
|
||||
} else {
|
||||
const QSet<QString> addedFiles = comparer.addedFiles();
|
||||
filesToReindex << addedFiles.toList();
|
||||
|
||||
const QSet<QString> modifiedFiles = comparer.timeStampModifiedFiles(snapshot());
|
||||
filesToReindex << modifiedFiles.toList();
|
||||
}
|
||||
|
||||
// Announce and purge the removed files from the snapshot
|
||||
const QSet<QString> removedFiles = comparer.removedFiles();
|
||||
if (!removedFiles.isEmpty()) {
|
||||
filesRemoved = true;
|
||||
emit aboutToRemoveFiles(removedFiles.toList());
|
||||
removeFilesFromSnapshot(removedFiles);
|
||||
}
|
||||
|
||||
// A new project was opened/created, do a full indexing
|
||||
} else {
|
||||
filesToReindex << newSourceFiles;
|
||||
}
|
||||
m_snapshot.remove(configurationFileName());
|
||||
|
||||
m_projectToProjectsInfo.insert(project, pinfo);
|
||||
// Update Project/ProjectInfo and File/ProjectPart table
|
||||
m_dirty = true;
|
||||
|
||||
m_projectToProjectsInfo.insert(project, newProjectInfo);
|
||||
m_fileToProjectParts.clear();
|
||||
foreach (const ProjectInfo &projectInfo, m_projectToProjectsInfo) {
|
||||
foreach (const ProjectPart::Ptr &projectPart, projectInfo.projectParts()) {
|
||||
@@ -625,14 +751,21 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &pinfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // Mutex scope
|
||||
|
||||
// If requested, dump everything we got
|
||||
if (!qgetenv("QTCREATOR_DUMP_PROJECT_INFO").isEmpty())
|
||||
dumpModelManagerConfiguration();
|
||||
|
||||
emit projectPartsUpdated(pinfo.project().data());
|
||||
// Remove files from snapshot that are not reachable any more
|
||||
if (filesRemoved)
|
||||
GC();
|
||||
|
||||
return updateSourceFiles(pinfo.sourceFiles(), ForcedProgressNotification);
|
||||
emit projectPartsUpdated(newProjectInfo.project().data());
|
||||
|
||||
// Trigger reindexing
|
||||
return updateSourceFiles(filesToReindex, ForcedProgressNotification);
|
||||
}
|
||||
|
||||
QList<ProjectPart::Ptr> CppModelManager::projectPart(const QString &fileName) const
|
||||
|
Reference in New Issue
Block a user