diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp index 5540a2f2dabebf963f2e05d5747c369b8379c2b6..adbb7b8bfa3d3322c3ebd0a4c915efc5ad09825e 100644 --- a/src/plugins/cpptools/cppmodelmanager.cpp +++ b/src/plugins/cpptools/cppmodelmanager.cpp @@ -300,6 +300,10 @@ CppModelManager::CppModelManager(QObject *parent) this, SLOT(onAboutToLoadSession())); connect(sessionManager, SIGNAL(aboutToUnloadSession(QString)), this, SLOT(onAboutToUnloadSession())); + + connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged, + this, &CppModelManager::onCurrentEditorChanged); + connect(Core::DocumentManager::instance(), &Core::DocumentManager::allDocumentsRenamed, this, &CppModelManager::renameIncludes); @@ -687,21 +691,32 @@ void CppModelManager::recalculateFileToProjectParts() } } -void CppModelManager::updateVisibleEditorDocuments() const +void CppModelManager::updateCppEditorDocuments() const { - QSet<QString> visibleDocumentsInEditMode; + // Refresh visible documents + QSet<Core::IDocument *> visibleCppEditorDocuments; foreach (Core::IEditor *editor, Core::EditorManager::visibleEditors()) { - if (const Core::IDocument *document = editor->document()) { + if (Core::IDocument *document = editor->document()) { const QString filePath = document->filePath(); - if (!filePath.isEmpty()) - visibleDocumentsInEditMode.insert(filePath); + if (filePath.isEmpty()) + continue; + if (EditorDocumentHandle *editor = editorDocument(filePath)) { + visibleCppEditorDocuments.insert(document); + editor->processor()->run(); + } } } - // Re-process these documents - foreach (const QString &filePath, visibleDocumentsInEditMode) { - if (EditorDocumentHandle *editor = editorDocument(filePath)) - editor->processor()->run(); + // Mark invisible documents dirty + QSet<Core::IDocument *> invisibleCppEditorDocuments + = Core::DocumentModel::openedDocuments().toSet(); + invisibleCppEditorDocuments.subtract(visibleCppEditorDocuments); + foreach (Core::IDocument *document, invisibleCppEditorDocuments) { + const QString filePath = document->filePath(); + if (filePath.isEmpty()) + continue; + if (EditorDocumentHandle *document = editorDocument(filePath)) + document->setNeedsRefresh(true); } } @@ -784,7 +799,7 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &newProjectIn // However, on e.g. a session restore first the editor documents are created and then the // project updates come in. That is, there are no reasonable dependency tables based on // resolved includes that we could rely on. - updateVisibleEditorDocuments(); + updateCppEditorDocuments(); // Trigger reindexing return updateSourceFiles(filesToReindex, ForcedProgressNotification); @@ -871,6 +886,19 @@ void CppModelManager::onSourceFilesRefreshed() const } } +void CppModelManager::onCurrentEditorChanged(Core::IEditor *editor) +{ + if (!editor || !editor->document()) + return; + + if (EditorDocumentHandle *cppEditorDocument = editorDocument(editor->document()->filePath())) { + if (cppEditorDocument->needsRefresh()) { + cppEditorDocument->setNeedsRefresh(false); + cppEditorDocument->processor()->run(); + } + } +} + void CppModelManager::onAboutToLoadSession() { if (d->m_delayedGcTimer.isActive()) diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h index e196be585e52609f924de86f3634f02be1ab8586..41acf2432555cd6374f626f329236eb1d87f1ea2 100644 --- a/src/plugins/cpptools/cppmodelmanager.h +++ b/src/plugins/cpptools/cppmodelmanager.h @@ -184,12 +184,13 @@ private slots: void onProjectAdded(ProjectExplorer::Project *project); void onAboutToRemoveProject(ProjectExplorer::Project *project); void onSourceFilesRefreshed() const; + void onCurrentEditorChanged(Core::IEditor *editor); void onCoreAboutToClose(); private: void delayedGC(); void recalculateFileToProjectParts(); - void updateVisibleEditorDocuments() const; + void updateCppEditorDocuments() const; void replaceSnapshot(const CPlusPlus::Snapshot &newSnapshot); void removeFilesFromSnapshot(const QSet<QString> &removedFiles); diff --git a/src/plugins/cpptools/cppmodelmanager_test.cpp b/src/plugins/cpptools/cppmodelmanager_test.cpp index b4065f13289520528d88d39dc87b2d2d002e908c..0e7b35f3643d0eb9e63b4da49937066248d16907 100644 --- a/src/plugins/cpptools/cppmodelmanager_test.cpp +++ b/src/plugins/cpptools/cppmodelmanager_test.cpp @@ -1037,6 +1037,69 @@ void CppToolsPlugin::test_modelmanager_defines_per_editor() } } +void CppToolsPlugin::test_modelmanager_updateEditorsAfterProjectUpdate() +{ + ModelManagerTestHelper helper; + CppModelManager *mm = CppModelManager::instance(); + + MyTestDataDir testDataDirectory(_("testdata_defines")); + const QString fileA = testDataDirectory.file(_("main1.cpp")); // content not relevant + const QString fileB = testDataDirectory.file(_("main2.cpp")); // content not relevant + + // Open file A in editor + Core::IEditor *editorA = Core::EditorManager::openEditor(fileA); + QVERIFY(editorA); + EditorCloser closerA(editorA); + QCOMPARE(Core::DocumentModel::openedDocuments().size(), 1); + + EditorDocumentHandle *editorDocumentA = mm->editorDocument(fileA); + QVERIFY(editorDocumentA); + ProjectPart::Ptr documentAProjectPart = editorDocumentA->processor()->parser()->projectPart(); + QVERIFY(!documentAProjectPart->project); + + // Open file B in editor + Core::IEditor *editorB = Core::EditorManager::openEditor(fileB); + QVERIFY(editorB); + EditorCloser closerB(editorB); + QCOMPARE(Core::DocumentModel::openedDocuments().size(), 2); + + EditorDocumentHandle *editorDocumentB = mm->editorDocument(fileB); + QVERIFY(editorDocumentB); + ProjectPart::Ptr documentBProjectPart = editorDocumentB->processor()->parser()->projectPart(); + QVERIFY(!documentBProjectPart->project); + + // Switch back to document A + Core::EditorManager::activateEditor(editorA); + + // Open/update related project + Project *project = helper.createProject(_("test_modelmanager_updateEditorsAfterProjectUpdate")); + + ProjectPart::Ptr part(new ProjectPart); + part->project = project; + part->files.append(ProjectFile(fileA, ProjectFile::CXXSource)); + part->files.append(ProjectFile(fileB, ProjectFile::CXXSource)); + part->languageVersion = ProjectPart::CXX11; + part->qtVersion = ProjectPart::NoQt; + + ProjectInfo pi = mm->projectInfo(project); + pi.appendProjectPart(part); + pi.finish(); + updateProjectInfo(mm, &helper, pi); + + // ... and check for updated editor document A + while (editorDocumentA->processor()->isParserRunning()) + QCoreApplication::processEvents(); + documentAProjectPart = editorDocumentA->processor()->parser()->projectPart(); + QCOMPARE(documentAProjectPart->project, project); + + // Switch back to document B and check if that's updated, too + Core::EditorManager::activateEditor(editorB); + while (editorDocumentB->processor()->isParserRunning()) + QCoreApplication::processEvents(); + documentBProjectPart = editorDocumentB->processor()->parser()->projectPart(); + QCOMPARE(documentBProjectPart->project, project); +} + void CppToolsPlugin::test_modelmanager_renameIncludes() { struct ModelManagerGCHelper { diff --git a/src/plugins/cpptools/cpptoolsplugin.h b/src/plugins/cpptools/cpptoolsplugin.h index c225a667fc821e17c26359c9a26b731af64014c6..a4200cc4de2c0ba5e517a891046fca69726cec64 100644 --- a/src/plugins/cpptools/cpptoolsplugin.h +++ b/src/plugins/cpptools/cpptoolsplugin.h @@ -151,6 +151,7 @@ private slots: void test_modelmanager_dont_gc_opened_files(); void test_modelmanager_defines_per_project(); void test_modelmanager_defines_per_editor(); + void test_modelmanager_updateEditorsAfterProjectUpdate(); void test_modelmanager_precompiled_headers(); void test_modelmanager_renameIncludes(); diff --git a/src/plugins/cpptools/editordocumenthandle.cpp b/src/plugins/cpptools/editordocumenthandle.cpp index 58d93372ca523218dda4de1ffb89aacc7e316acc..9e40aca5b2d247a8e96dcd7517405c1f271f137c 100644 --- a/src/plugins/cpptools/editordocumenthandle.cpp +++ b/src/plugins/cpptools/editordocumenthandle.cpp @@ -40,6 +40,7 @@ namespace CppTools { */ EditorDocumentHandle::EditorDocumentHandle() + : m_needsRefresh(false) { } @@ -47,4 +48,14 @@ EditorDocumentHandle::~EditorDocumentHandle() { } +bool EditorDocumentHandle::needsRefresh() const +{ + return m_needsRefresh; +} + +void EditorDocumentHandle::setNeedsRefresh(bool needsRefresh) +{ + m_needsRefresh = needsRefresh; +} + } // namespace CppTools diff --git a/src/plugins/cpptools/editordocumenthandle.h b/src/plugins/cpptools/editordocumenthandle.h index aa265f91be88ead5ff48cd8818fe5142d1ede461..d40fd0e9ed81c487d39bce83182308fbc02f24b3 100644 --- a/src/plugins/cpptools/editordocumenthandle.h +++ b/src/plugins/cpptools/editordocumenthandle.h @@ -42,6 +42,9 @@ public: EditorDocumentHandle(); virtual ~EditorDocumentHandle(); + bool needsRefresh() const; + void setNeedsRefresh(bool needsRefresh); + // For the Working Copy virtual QString filePath() const = 0; virtual QByteArray contents() const = 0; @@ -49,6 +52,9 @@ public: // For updating if new project info is set virtual BaseEditorDocumentProcessor *processor() = 0; + +private: + bool m_needsRefresh; }; } // namespace CppTools