forked from qt-creator/qt-creator
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:
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user