Clang: Fix sending (un)register translation unit

Handle the following use cases:

  1. Editor is opened
    --> Register file at backend.

  2. Close editor for which a project part exists
    --> Unregister file with project part.

  3. Close editor for which no project part exists (anymore)
    --> Unregister file with empty/default project part.

Change-Id: I2b253004a920cccef989876538ab552eacf6b45c
Reviewed-by: Marco Bubke <marco.bubke@theqtcompany.com>
This commit is contained in:
Nikolai Kosjar
2015-07-14 19:01:32 +02:00
parent 7e7e79dedc
commit c6b52267f4
6 changed files with 106 additions and 14 deletions

View File

@@ -86,6 +86,9 @@ ClangEditorDocumentParser::ClangEditorDocumentParser(const QString &filePath)
: BaseEditorDocumentParser(filePath) : BaseEditorDocumentParser(filePath)
, m_marker(new ClangCodeModel::SemanticMarker) , m_marker(new ClangCodeModel::SemanticMarker)
{ {
BaseEditorDocumentParser::Configuration config = configuration();
config.stickToPreviousProjectPart = false;
setConfiguration(config);
} }
void ClangEditorDocumentParser::updateHelper(const BaseEditorDocumentParser::InMemoryInfo &info) void ClangEditorDocumentParser::updateHelper(const BaseEditorDocumentParser::InMemoryInfo &info)

View File

@@ -112,6 +112,9 @@ ClangEditorDocumentProcessor::ClangEditorDocumentProcessor(
connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::semanticInfoUpdated, connect(&m_builtinProcessor, &CppTools::BuiltinEditorDocumentProcessor::semanticInfoUpdated,
this, &ClangEditorDocumentProcessor::semanticInfoUpdated); this, &ClangEditorDocumentProcessor::semanticInfoUpdated);
connect(CppTools::CppModelManager::instance(), &CppTools::CppModelManager::projectPartsRemoved,
this, &ClangEditorDocumentProcessor::onProjectPartsRemoved);
m_semanticHighlighter.setHighlightingRunner( m_semanticHighlighter.setHighlightingRunner(
[this]() -> QFuture<TextEditor::HighlightingResult> { [this]() -> QFuture<TextEditor::HighlightingResult> {
const int firstLine = 1; const int firstLine = 1;
@@ -129,16 +132,11 @@ ClangEditorDocumentProcessor::~ClangEditorDocumentProcessor()
m_parserWatcher.cancel(); m_parserWatcher.cancel();
m_parserWatcher.waitForFinished(); m_parserWatcher.waitForFinished();
const CppTools::ProjectPart::Ptr projectPart = m_parser.projectPart(); if (m_projectPart) {
QTC_ASSERT(projectPart, return); QTC_ASSERT(m_modelManagerSupport, return);
m_modelManagerSupport->ipcCommunicator().unregisterFilesForCodeCompletion(
QString projectPartId; {ClangBackEnd::FileContainer(filePath(), m_projectPart->id())});
if (Utils::isProjectPartValid(projectPart)) }
projectPartId = projectPart->id(); // OK, Project Part is still loaded
QTC_ASSERT(m_modelManagerSupport, return);
m_modelManagerSupport->ipcCommunicator().unregisterFilesForCodeCompletion(
{ClangBackEnd::FileContainer(filePath(), projectPartId)});
} }
void ClangEditorDocumentProcessor::run() void ClangEditorDocumentProcessor::run()
@@ -192,6 +190,25 @@ bool ClangEditorDocumentProcessor::isParserRunning() const
return m_parserWatcher.isRunning(); return m_parserWatcher.isRunning();
} }
CppTools::ProjectPart::Ptr ClangEditorDocumentProcessor::projectPart() const
{
return m_projectPart;
}
ClangEditorDocumentProcessor *ClangEditorDocumentProcessor::get(const QString &filePath)
{
return qobject_cast<ClangEditorDocumentProcessor *>(BaseEditorDocumentProcessor::get(filePath));
}
void ClangEditorDocumentProcessor::updateProjectPartAndTranslationUnitForCompletion()
{
const CppTools::ProjectPart::Ptr projectPart = m_parser.projectPart();
QTC_ASSERT(projectPart, return);
updateTranslationUnitForCompletion(*projectPart.data());
m_projectPart = projectPart;
}
void ClangEditorDocumentProcessor::onParserFinished() void ClangEditorDocumentProcessor::onParserFinished()
{ {
if (revision() != m_parserRevision) if (revision() != m_parserRevision)
@@ -208,6 +225,34 @@ void ClangEditorDocumentProcessor::onParserFinished()
// Run semantic highlighter // Run semantic highlighter
m_semanticHighlighter.run(); m_semanticHighlighter.run();
updateProjectPartAndTranslationUnitForCompletion();
}
void ClangEditorDocumentProcessor::onProjectPartsRemoved(const QStringList &projectPartIds)
{
if (m_projectPart && projectPartIds.contains(m_projectPart->id()))
m_projectPart.clear();
}
void ClangEditorDocumentProcessor::updateTranslationUnitForCompletion(
CppTools::ProjectPart &projectPart)
{
QTC_ASSERT(m_modelManagerSupport, return);
IpcCommunicator &ipcCommunicator = m_modelManagerSupport->ipcCommunicator();
if (m_projectPart) {
if (projectPart.id() != m_projectPart->id()) {
auto container1 = {ClangBackEnd::FileContainer(filePath(), m_projectPart->id())};
ipcCommunicator.unregisterFilesForCodeCompletion(container1);
auto container2 = {ClangBackEnd::FileContainer(filePath(), projectPart.id())};
ipcCommunicator.registerFilesForCodeCompletion(container2);
}
} else {
auto container = {ClangBackEnd::FileContainer(filePath(), projectPart.id())};
ipcCommunicator.registerFilesForCodeCompletion(container);
}
} }
} // namespace Internal } // namespace Internal

View File

@@ -63,13 +63,23 @@ public:
CPlusPlus::Snapshot snapshot() override; CPlusPlus::Snapshot snapshot() override;
bool isParserRunning() const override; bool isParserRunning() const override;
CppTools::ProjectPart::Ptr projectPart() const;
public:
static ClangEditorDocumentProcessor *get(const QString &filePath);
private slots: private slots:
void onParserFinished(); void onParserFinished();
void onProjectPartsRemoved(const QStringList &projectPartIds);
private: private:
void updateProjectPartAndTranslationUnitForCompletion();
void updateTranslationUnitForCompletion(CppTools::ProjectPart &projectPart);
QPointer<ModelManagerSupportClang> m_modelManagerSupport; QPointer<ModelManagerSupportClang> m_modelManagerSupport;
ClangEditorDocumentParser m_parser; ClangEditorDocumentParser m_parser;
CppTools::ProjectPart::Ptr m_projectPart;
QFutureWatcher<void> m_parserWatcher; QFutureWatcher<void> m_parserWatcher;
unsigned m_parserRevision; unsigned m_parserRevision;

View File

@@ -34,6 +34,7 @@
#include "../clangcompletionassistinterface.h" #include "../clangcompletionassistinterface.h"
#include "../clangmodelmanagersupport.h" #include "../clangmodelmanagersupport.h"
#include <clangcodemodel/clangeditordocumentprocessor.h>
#include <clangcodemodel/constants.h> #include <clangcodemodel/constants.h>
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
@@ -476,11 +477,13 @@ public:
OpenEditorAtCursorPosition(const TestDocument &testDocument); OpenEditorAtCursorPosition(const TestDocument &testDocument);
~OpenEditorAtCursorPosition(); // Close editor ~OpenEditorAtCursorPosition(); // Close editor
bool succeeded() const { return m_editor; } bool succeeded() const { return m_editor && m_backendIsNotified; }
bool waitUntilBackendIsNotified(int timeout = 10000);
TextEditor::BaseTextEditor *editor() const { return m_editor; } TextEditor::BaseTextEditor *editor() const { return m_editor; }
private: private:
TextEditor::BaseTextEditor *m_editor; TextEditor::BaseTextEditor *m_editor;
bool m_backendIsNotified = false;
}; };
OpenEditorAtCursorPosition::OpenEditorAtCursorPosition(const TestDocument &testDocument) OpenEditorAtCursorPosition::OpenEditorAtCursorPosition(const TestDocument &testDocument)
@@ -490,6 +493,8 @@ OpenEditorAtCursorPosition::OpenEditorAtCursorPosition(const TestDocument &testD
QTC_CHECK(m_editor); QTC_CHECK(m_editor);
if (m_editor && testDocument.hasValidCursorPosition()) if (m_editor && testDocument.hasValidCursorPosition())
m_editor->setCursorPosition(testDocument.cursorPosition); m_editor->setCursorPosition(testDocument.cursorPosition);
m_backendIsNotified = waitUntilBackendIsNotified();
QTC_CHECK(m_backendIsNotified);
} }
OpenEditorAtCursorPosition::~OpenEditorAtCursorPosition() OpenEditorAtCursorPosition::~OpenEditorAtCursorPosition()
@@ -498,6 +503,30 @@ OpenEditorAtCursorPosition::~OpenEditorAtCursorPosition()
Core::EditorManager::closeEditor(m_editor, /* askAboutModifiedEditors= */ false); Core::EditorManager::closeEditor(m_editor, /* askAboutModifiedEditors= */ false);
} }
bool OpenEditorAtCursorPosition::waitUntilBackendIsNotified(int timeout)
{
QTC_ASSERT(m_editor, return false);
const QString filePath = m_editor->document()->filePath().toString();
QTime time;
time.start();
forever {
if (time.elapsed() > timeout)
return false;
const auto *processor = ClangEditorDocumentProcessor::get(filePath);
if (processor && processor->projectPart())
return true;
QCoreApplication::processEvents();
QThread::msleep(20);
}
return false;
}
CppTools::ProjectPart::Ptr createProjectPart(const QStringList &files, CppTools::ProjectPart::Ptr createProjectPart(const QStringList &files,
const QString &defines) const QString &defines)
{ {
@@ -1036,23 +1065,27 @@ void ClangCodeCompletionTest::testUpdateBackendAfterRestart()
CppTools::Tests::ProjectOpenerAndCloser projectManager; CppTools::Tests::ProjectOpenerAndCloser projectManager;
const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true); const CppTools::ProjectInfo projectInfo = projectManager.open(projectFilePath, true);
QVERIFY(projectInfo.isValid()); QVERIFY(projectInfo.isValid());
QVERIFY(monitorGeneratedUiFile.waitUntilGenerated());
// ...and a file of the project // ...and a file of the project
const QString completionFile = testDir.absolutePath("mainwindow.cpp"); const QString completionFile = testDir.absolutePath("mainwindow.cpp");
const TestDocument testDocument = TestDocument::fromExistingFile(completionFile); const TestDocument testDocument = TestDocument::fromExistingFile(completionFile);
QVERIFY(testDocument.isCreatedAndHasValidCursorPosition()); QVERIFY(testDocument.isCreatedAndHasValidCursorPosition());
OpenEditorAtCursorPosition openSource(testDocument); OpenEditorAtCursorPosition openSource(testDocument);
QVERIFY(openSource.succeeded()); QVERIFY(openSource.succeeded());
QVERIFY(monitorGeneratedUiFile.waitUntilGenerated());
// Check commands that would have been sent // Check commands that would have been sent
QVERIFY(compare(LogOutput(spy.senderLog), QVERIFY(compare(LogOutput(spy.senderLog),
LogOutput( LogOutput(
"RegisterTranslationUnitForCodeCompletionCommand\n"
" Path: myheader.h ProjectPart: \n"
"RegisterProjectPartsForCodeCompletionCommand\n" "RegisterProjectPartsForCodeCompletionCommand\n"
" ProjectPartContainer id: qt-widgets-app.pro qt-widgets-app\n" " ProjectPartContainer id: qt-widgets-app.pro qt-widgets-app\n"
"RegisterTranslationUnitForCodeCompletionCommand\n" "RegisterTranslationUnitForCodeCompletionCommand\n"
" Path: ui_mainwindow.h ProjectPart: \n"
"RegisterTranslationUnitForCodeCompletionCommand\n"
" Path: myheader.h ProjectPart: \n" " Path: myheader.h ProjectPart: \n"
"RegisterTranslationUnitForCodeCompletionCommand\n" "RegisterTranslationUnitForCodeCompletionCommand\n"
" Path: ui_mainwindow.h ProjectPart: \n" " Path: mainwindow.cpp ProjectPart: qt-widgets-app.pro qt-widgets-app\n"
))); )));
spy.senderLog.clear(); spy.senderLog.clear();

View File

@@ -126,7 +126,7 @@ ProjectPart::Ptr BaseEditorDocumentParser::determineProjectPart(const QString &f
CppModelManager *cmm = CppModelManager::instance(); CppModelManager *cmm = CppModelManager::instance();
QList<ProjectPart::Ptr> projectParts = cmm->projectPart(filePath); QList<ProjectPart::Ptr> projectParts = cmm->projectPart(filePath);
if (projectParts.isEmpty()) { if (projectParts.isEmpty()) {
if (projectPart) if (projectPart && config.stickToPreviousProjectPart)
// File is not directly part of any project, but we got one before. We will re-use it, // File is not directly part of any project, but we got one before. We will re-use it,
// because re-calculating this can be expensive when the dependency table is big. // because re-calculating this can be expensive when the dependency table is big.
return projectPart; return projectPart;

View File

@@ -47,6 +47,7 @@ public:
static BaseEditorDocumentParser *get(const QString &filePath); static BaseEditorDocumentParser *get(const QString &filePath);
struct Configuration { struct Configuration {
bool stickToPreviousProjectPart = true;
bool usePrecompiledHeaders = false; bool usePrecompiledHeaders = false;
QByteArray editorDefines; QByteArray editorDefines;
ProjectPart::Ptr manuallySetProjectPart; ProjectPart::Ptr manuallySetProjectPart;