Clang: Fix slowness of code completion after opening the file

Task-number: QTCREATORBUG-15429
Change-Id: I9a8a582fb3c59a960425f83eb8e7b436f15d1c1a
Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
Marco Bubke
2015-12-02 13:31:07 +01:00
parent 48a2e15c28
commit 493a2a6189
14 changed files with 126 additions and 37 deletions

View File

@@ -39,8 +39,12 @@
namespace ClangBackEnd { namespace ClangBackEnd {
RegisterTranslationUnitForEditorMessage::RegisterTranslationUnitForEditorMessage(const QVector<FileContainer> &fileContainers) RegisterTranslationUnitForEditorMessage::RegisterTranslationUnitForEditorMessage(const QVector<FileContainer> &fileContainers,
: fileContainers_(fileContainers) const Utf8String &currentEditorFilePath,
const Utf8StringVector &visibleEditorFilePaths)
: fileContainers_(fileContainers),
currentEditorFilePath_(currentEditorFilePath),
visibleEditorFilePaths_(visibleEditorFilePaths)
{ {
} }
@@ -49,28 +53,45 @@ const QVector<FileContainer> &RegisterTranslationUnitForEditorMessage::fileConta
return fileContainers_; return fileContainers_;
} }
const Utf8String &RegisterTranslationUnitForEditorMessage::currentEditorFilePath() const
{
return currentEditorFilePath_;
}
const Utf8StringVector &RegisterTranslationUnitForEditorMessage::visibleEditorFilePaths() const
{
return visibleEditorFilePaths_;
}
QDataStream &operator<<(QDataStream &out, const RegisterTranslationUnitForEditorMessage &message) QDataStream &operator<<(QDataStream &out, const RegisterTranslationUnitForEditorMessage &message)
{ {
out << message.fileContainers_; out << message.fileContainers_;
out << message.currentEditorFilePath_;
out << message.visibleEditorFilePaths_;
return out; return out;
} }
QDataStream &operator>>(QDataStream &in, RegisterTranslationUnitForEditorMessage &message) QDataStream &operator>>(QDataStream &in, RegisterTranslationUnitForEditorMessage &message)
{ {
in >> message.fileContainers_; in >> message.fileContainers_;
in >> message.currentEditorFilePath_;
in >> message.visibleEditorFilePaths_;
return in; return in;
} }
bool operator==(const RegisterTranslationUnitForEditorMessage &first, const RegisterTranslationUnitForEditorMessage &second) bool operator==(const RegisterTranslationUnitForEditorMessage &first, const RegisterTranslationUnitForEditorMessage &second)
{ {
return first.fileContainers_ == second.fileContainers_; return first.fileContainers_ == second.fileContainers_
&& first.currentEditorFilePath_ == second.currentEditorFilePath_
&& first.visibleEditorFilePaths_ == second.visibleEditorFilePaths_;
} }
bool operator<(const RegisterTranslationUnitForEditorMessage &first, const RegisterTranslationUnitForEditorMessage &second) bool operator<(const RegisterTranslationUnitForEditorMessage &first, const RegisterTranslationUnitForEditorMessage &second)
{ {
return compareContainer(first.fileContainers_, second.fileContainers_); return compareContainer(first.fileContainers_, second.fileContainers_)
&& first.currentEditorFilePath_ < second.currentEditorFilePath_
&& compareContainer(first.visibleEditorFilePaths_, second.visibleEditorFilePaths_);
} }
QDebug operator<<(QDebug debug, const RegisterTranslationUnitForEditorMessage &message) QDebug operator<<(QDebug debug, const RegisterTranslationUnitForEditorMessage &message)
@@ -80,6 +101,11 @@ QDebug operator<<(QDebug debug, const RegisterTranslationUnitForEditorMessage &m
for (const FileContainer &fileContainer : message.fileContainers()) for (const FileContainer &fileContainer : message.fileContainers())
debug.nospace() << fileContainer<< ", "; debug.nospace() << fileContainer<< ", ";
debug.nospace() << message.currentEditorFilePath() << ", ";
for (const Utf8String &visibleEditorFilePath : message.visibleEditorFilePaths())
debug.nospace() << visibleEditorFilePath << ", ";
debug.nospace() << ")"; debug.nospace() << ")";
return debug; return debug;
@@ -92,6 +118,12 @@ void PrintTo(const RegisterTranslationUnitForEditorMessage &message, ::std::ostr
for (const FileContainer &fileContainer : message.fileContainers()) for (const FileContainer &fileContainer : message.fileContainers())
PrintTo(fileContainer, os); PrintTo(fileContainer, os);
*os << message.currentEditorFilePath().constData() << ", ";
auto visiblePaths = message.visibleEditorFilePaths();
std::copy(visiblePaths.cbegin(), visiblePaths.cend(), std::ostream_iterator<Utf8String>(*os, ", "));
*os << ")"; *os << ")";
} }

View File

@@ -47,12 +47,18 @@ class CMBIPC_EXPORT RegisterTranslationUnitForEditorMessage
friend void PrintTo(const RegisterTranslationUnitForEditorMessage &message, ::std::ostream* os); friend void PrintTo(const RegisterTranslationUnitForEditorMessage &message, ::std::ostream* os);
public: public:
RegisterTranslationUnitForEditorMessage() = default; RegisterTranslationUnitForEditorMessage() = default;
RegisterTranslationUnitForEditorMessage(const QVector<FileContainer> &fileContainers); RegisterTranslationUnitForEditorMessage(const QVector<FileContainer> &fileContainers,
const Utf8String &currentEditorFilePath,
const Utf8StringVector &visibleEditorFilePaths);
const QVector<FileContainer> &fileContainers() const; const QVector<FileContainer> &fileContainers() const;
const Utf8String &currentEditorFilePath() const;
const Utf8StringVector &visibleEditorFilePaths() const;
private: private:
QVector<FileContainer> fileContainers_; QVector<FileContainer> fileContainers_;
Utf8String currentEditorFilePath_;
Utf8StringVector visibleEditorFilePaths_;
}; };
CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const RegisterTranslationUnitForEditorMessage &message); CMBIPC_EXPORT QDataStream &operator<<(QDataStream &out, const RegisterTranslationUnitForEditorMessage &message);

View File

@@ -670,7 +670,9 @@ void IpcCommunicator::registerTranslationUnitsForEditor(const FileContainers &fi
if (m_sendMode == IgnoreSendRequests) if (m_sendMode == IgnoreSendRequests)
return; return;
const RegisterTranslationUnitForEditorMessage message(fileContainers); const RegisterTranslationUnitForEditorMessage message(fileContainers,
currentCppEditorDocumentFilePath(),
visibleCppEditorDocumentsFilePaths());
qCDebug(log) << ">>>" << message; qCDebug(log) << ">>>" << message;
m_ipcSender->registerTranslationUnitsForEditor(message); m_ipcSender->registerTranslationUnitsForEditor(message);
} }

View File

@@ -268,13 +268,9 @@ void ClangEditorDocumentProcessor::registerTranslationUnitForEditor(CppTools::Pr
if (projectPart->id() != m_projectPart->id()) { if (projectPart->id() != m_projectPart->id()) {
ipcCommunicator.unregisterTranslationUnitsForEditor({fileContainerWithArguments()}); ipcCommunicator.unregisterTranslationUnitsForEditor({fileContainerWithArguments()});
ipcCommunicator.registerTranslationUnitsForEditor({fileContainerWithArguments(projectPart)}); ipcCommunicator.registerTranslationUnitsForEditor({fileContainerWithArguments(projectPart)});
ipcCommunicator.updateTranslationUnitVisiblity();
requestDocumentAnnotations(projectPart->id());
} }
} else { } else {
ipcCommunicator.registerTranslationUnitsForEditor({{fileContainerWithArguments(projectPart)}}); ipcCommunicator.registerTranslationUnitsForEditor({{fileContainerWithArguments(projectPart)}});
ipcCommunicator.updateTranslationUnitVisiblity();
requestDocumentAnnotations(projectPart->id());
} }
} }

View File

@@ -1063,6 +1063,8 @@ void ClangCodeCompletionTest::testCompleteProjectDependingCodeInGeneratedUiFile(
void ClangCodeCompletionTest::testCompleteAfterModifyingIncludedHeaderInOtherEditor() void ClangCodeCompletionTest::testCompleteAfterModifyingIncludedHeaderInOtherEditor()
{ {
QSKIP("We don't reparse anymore before a code completion so we get wrong completion results.");
CppTools::Tests::TemporaryDir temporaryDir; CppTools::Tests::TemporaryDir temporaryDir;
const TestDocument sourceDocument("mysource.cpp", &temporaryDir); const TestDocument sourceDocument("mysource.cpp", &temporaryDir);
QVERIFY(sourceDocument.isCreatedAndHasValidCursorPosition()); QVERIFY(sourceDocument.isCreatedAndHasValidCursorPosition());
@@ -1090,6 +1092,8 @@ void ClangCodeCompletionTest::testCompleteAfterModifyingIncludedHeaderInOtherEdi
void ClangCodeCompletionTest::testCompleteAfterModifyingIncludedHeaderByRefactoringActions() void ClangCodeCompletionTest::testCompleteAfterModifyingIncludedHeaderByRefactoringActions()
{ {
QSKIP("We don't reparse anymore before a code completion so we get wrong completion results.");
CppTools::Tests::TemporaryDir temporaryDir; CppTools::Tests::TemporaryDir temporaryDir;
const TestDocument sourceDocument("mysource.cpp", &temporaryDir); const TestDocument sourceDocument("mysource.cpp", &temporaryDir);
QVERIFY(sourceDocument.isCreatedAndHasValidCursorPosition()); QVERIFY(sourceDocument.isCreatedAndHasValidCursorPosition());

View File

@@ -116,9 +116,12 @@ void ClangIpcServer::registerTranslationUnitsForEditor(const ClangBackEnd::Regis
TIME_SCOPE_DURATION("ClangIpcServer::registerTranslationUnitsForEditor"); TIME_SCOPE_DURATION("ClangIpcServer::registerTranslationUnitsForEditor");
try { try {
translationUnits.create(message.fileContainers()); auto createdTranslationUnits = translationUnits.create(message.fileContainers());
unsavedFiles.createOrUpdate(message.fileContainers()); unsavedFiles.createOrUpdate(message.fileContainers());
sendDocumentAnnotationsTimer.start(0); translationUnits.setUsedByCurrentEditor(message.currentEditorFilePath());
translationUnits.setVisibleInEditors(message.visibleEditorFilePaths());
startDocumentAnnotations();
reparseVisibleDocuments(createdTranslationUnits);
} catch (const ProjectPartDoNotExistException &exception) { } catch (const ProjectPartDoNotExistException &exception) {
client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds())); client()->projectPartsDoNotExist(ProjectPartsDoNotExistMessage(exception.projectPartIds()));
} catch (const std::exception &exception) { } catch (const std::exception &exception) {
@@ -299,4 +302,19 @@ void ClangIpcServer::startDocumentAnnotationsTimerIfFileIsNotATranslationUnit(co
sendDocumentAnnotationsTimer.start(0); sendDocumentAnnotationsTimer.start(0);
} }
void ClangIpcServer::startDocumentAnnotations()
{
DocumentAnnotationsSendState sendState = DocumentAnnotationsSendState::MaybeThereAreDocumentAnnotations;
while (sendState == DocumentAnnotationsSendState::MaybeThereAreDocumentAnnotations)
sendState = translationUnits.sendDocumentAnnotations();
}
void ClangIpcServer::reparseVisibleDocuments(std::vector<TranslationUnit> &translationUnits)
{
for (TranslationUnit &translationUnit : translationUnits)
if (translationUnit.isVisibleInEditor())
translationUnit.reparse();
}
} }

View File

@@ -68,6 +68,8 @@ public:
private: private:
void startDocumentAnnotationsTimerIfFileIsNotATranslationUnit(const Utf8String &filePath); void startDocumentAnnotationsTimerIfFileIsNotATranslationUnit(const Utf8String &filePath);
void startDocumentAnnotations();
void reparseVisibleDocuments(std::vector<TranslationUnit> &translationUnits);
private: private:
ProjectParts projects; ProjectParts projects;

View File

@@ -63,12 +63,16 @@ TranslationUnits::TranslationUnits(ProjectParts &projects, UnsavedFiles &unsaved
{ {
} }
void TranslationUnits::create(const QVector<FileContainer> &fileContainers) std::vector<TranslationUnit> TranslationUnits::create(const QVector<FileContainer> &fileContainers)
{ {
checkIfTranslationUnitsDoesNotExists(fileContainers); checkIfTranslationUnitsDoesNotExists(fileContainers);
std::vector<TranslationUnit> createdTranslationUnits;
for (const FileContainer &fileContainer : fileContainers) for (const FileContainer &fileContainer : fileContainers)
createTranslationUnit(fileContainer); createdTranslationUnits.push_back(createTranslationUnit(fileContainer));
return createdTranslationUnits;
} }
void TranslationUnits::update(const QVector<FileContainer> &fileContainers) void TranslationUnits::update(const QVector<FileContainer> &fileContainers)
@@ -258,18 +262,19 @@ const ClangFileSystemWatcher *TranslationUnits::clangFileSystemWatcher() const
return &fileSystemWatcher; return &fileSystemWatcher;
} }
void TranslationUnits::createTranslationUnit(const FileContainer &fileContainer) TranslationUnit TranslationUnits::createTranslationUnit(const FileContainer &fileContainer)
{ {
TranslationUnit::FileExistsCheck checkIfFileExists = fileContainer.hasUnsavedFileContent() ? TranslationUnit::DoNotCheckIfFileExists : TranslationUnit::CheckIfFileExists; TranslationUnit::FileExistsCheck checkIfFileExists = fileContainer.hasUnsavedFileContent() ? TranslationUnit::DoNotCheckIfFileExists : TranslationUnit::CheckIfFileExists;
auto findIterator = findTranslationUnit(fileContainer);
if (findIterator == translationUnits_.end()) { translationUnits_.emplace_back(fileContainer.filePath(),
translationUnits_.push_back(TranslationUnit(fileContainer.filePath(), projectParts.project(fileContainer.projectPartId()),
projectParts.project(fileContainer.projectPartId()), fileContainer.fileArguments(),
fileContainer.fileArguments(), *this,
*this, checkIfFileExists);
checkIfFileExists));
translationUnits_.back().setDocumentRevision(fileContainer.documentRevision()); translationUnits_.back().setDocumentRevision(fileContainer.documentRevision());
}
return translationUnits_.back();
} }
void TranslationUnits::updateTranslationUnit(const FileContainer &fileContainer) void TranslationUnits::updateTranslationUnit(const FileContainer &fileContainer)

View File

@@ -64,7 +64,7 @@ public:
public: public:
TranslationUnits(ProjectParts &projectParts, UnsavedFiles &unsavedFiles); TranslationUnits(ProjectParts &projectParts, UnsavedFiles &unsavedFiles);
void create(const QVector<FileContainer> &fileContainers); std::vector<TranslationUnit> create(const QVector<FileContainer> &fileContainers);
void update(const QVector<FileContainer> &fileContainers); void update(const QVector<FileContainer> &fileContainers);
void remove(const QVector<FileContainer> &fileContainers); void remove(const QVector<FileContainer> &fileContainers);
@@ -96,7 +96,7 @@ public:
const ClangFileSystemWatcher *clangFileSystemWatcher() const; const ClangFileSystemWatcher *clangFileSystemWatcher() const;
private: private:
void createTranslationUnit(const FileContainer &fileContainer); TranslationUnit createTranslationUnit(const FileContainer &fileContainer);
void updateTranslationUnit(const FileContainer &fileContainer); void updateTranslationUnit(const FileContainer &fileContainer);
std::vector<TranslationUnit>::iterator findTranslationUnit(const FileContainer &fileContainer); std::vector<TranslationUnit>::iterator findTranslationUnit(const FileContainer &fileContainer);
std::vector<TranslationUnit>::iterator findAllTranslationUnitWithFilePath(const Utf8String &filePath); std::vector<TranslationUnit>::iterator findAllTranslationUnitWithFilePath(const Utf8String &filePath);

View File

@@ -332,7 +332,9 @@ TEST_F(ClangIpcServer, GetProjectPartDoesNotExistUnregisterProjectPartInexisting
TEST_F(ClangIpcServer, GetProjectPartDoesNotExistRegisterTranslationUnitWithInexistingProjectPart) TEST_F(ClangIpcServer, GetProjectPartDoesNotExistRegisterTranslationUnitWithInexistingProjectPart)
{ {
Utf8String inexistingProjectPartFilePath = Utf8StringLiteral("projectpartsdoesnotexist.pro"); Utf8String inexistingProjectPartFilePath = Utf8StringLiteral("projectpartsdoesnotexist.pro");
RegisterTranslationUnitForEditorMessage registerFileForEditorMessage({FileContainer(variableTestFilePath, inexistingProjectPartFilePath)}); RegisterTranslationUnitForEditorMessage registerFileForEditorMessage({FileContainer(variableTestFilePath, inexistingProjectPartFilePath)},
variableTestFilePath,
{variableTestFilePath});
ProjectPartsDoNotExistMessage projectPartsDoNotExistMessage({inexistingProjectPartFilePath}); ProjectPartsDoNotExistMessage projectPartsDoNotExistMessage({inexistingProjectPartFilePath});
EXPECT_CALL(mockIpcClient, projectPartsDoNotExist(projectPartsDoNotExistMessage)) EXPECT_CALL(mockIpcClient, projectPartsDoNotExist(projectPartsDoNotExistMessage))
@@ -398,9 +400,9 @@ TEST_F(ClangIpcServer, TicketNumberIsForwarded)
clangServer.completeCode(completeCodeMessage); clangServer.completeCode(completeCodeMessage);
} }
TEST_F(ClangIpcServer, TranslationUnitAfterCreationNeedsNoReparseAndHasNewDiagnostics) TEST_F(ClangIpcServer, TranslationUnitAfterCreationNeedsNoReparseAndHasNoNewDiagnostics)
{ {
ASSERT_THAT(clangServer, HasDirtyTranslationUnit(functionTestFilePath, projectPartId, 0U, false, true)); ASSERT_THAT(clangServer, HasDirtyTranslationUnit(functionTestFilePath, projectPartId, 0U, false, false));
} }
TEST_F(ClangIpcServer, SetCurrentAndVisibleEditor) TEST_F(ClangIpcServer, SetCurrentAndVisibleEditor)
@@ -439,7 +441,12 @@ void ClangIpcServer::SetUp()
void ClangIpcServer::registerFiles() void ClangIpcServer::registerFiles()
{ {
RegisterTranslationUnitForEditorMessage message({FileContainer(functionTestFilePath, projectPartId, unsavedContent(unsavedTestFilePath), true), RegisterTranslationUnitForEditorMessage message({FileContainer(functionTestFilePath, projectPartId, unsavedContent(unsavedTestFilePath), true),
FileContainer(variableTestFilePath, projectPartId)}); FileContainer(variableTestFilePath, projectPartId)},
functionTestFilePath,
{functionTestFilePath, variableTestFilePath});
EXPECT_CALL(mockIpcClient, diagnosticsChanged(_)).Times(2);
EXPECT_CALL(mockIpcClient, highlightingChanged(_)).Times(2);
clangServer.registerTranslationUnitsForEditor(message); clangServer.registerTranslationUnitsForEditor(message);
} }

View File

@@ -90,7 +90,8 @@ protected:
void scheduleClientMessages(); void scheduleClientMessages();
protected: protected:
ClangBackEnd::FileContainer fileContainer{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp"), Utf8String filePath{Utf8StringLiteral(TESTDATA_DIR"/complete_extractor_function.cpp")};
ClangBackEnd::FileContainer fileContainer{filePath,
Utf8StringLiteral("projectPartId"), Utf8StringLiteral("projectPartId"),
Utf8StringLiteral("unsaved content"), Utf8StringLiteral("unsaved content"),
true, true,
@@ -123,7 +124,9 @@ TEST_F(ClientServerInProcess, SendAliveMessage)
TEST_F(ClientServerInProcess, SendRegisterTranslationUnitForEditorMessage) TEST_F(ClientServerInProcess, SendRegisterTranslationUnitForEditorMessage)
{ {
ClangBackEnd::RegisterTranslationUnitForEditorMessage message({fileContainer}); ClangBackEnd::RegisterTranslationUnitForEditorMessage message({fileContainer},
filePath,
{filePath});
EXPECT_CALL(mockIpcServer, registerTranslationUnitsForEditor(message)) EXPECT_CALL(mockIpcServer, registerTranslationUnitsForEditor(message))
.Times(1); .Times(1);

View File

@@ -115,8 +115,11 @@ TEST_F(ClientServerOutsideProcess, RestartProcessAfterTermination)
TEST_F(ClientServerOutsideProcess, SendRegisterTranslationUnitForEditorMessage) TEST_F(ClientServerOutsideProcess, SendRegisterTranslationUnitForEditorMessage)
{ {
ClangBackEnd::FileContainer fileContainer(Utf8StringLiteral("foo.cpp"), Utf8StringLiteral("projectId")); auto filePath = Utf8StringLiteral("foo.cpp");
ClangBackEnd::RegisterTranslationUnitForEditorMessage registerTranslationUnitForEditorMessage({fileContainer}); ClangBackEnd::FileContainer fileContainer(filePath, Utf8StringLiteral("projectId"));
ClangBackEnd::RegisterTranslationUnitForEditorMessage registerTranslationUnitForEditorMessage({fileContainer},
filePath,
{filePath});
EchoMessage echoMessage(QVariant::fromValue(registerTranslationUnitForEditorMessage)); EchoMessage echoMessage(QVariant::fromValue(registerTranslationUnitForEditorMessage));
EXPECT_CALL(mockIpcClient, echo(echoMessage)) EXPECT_CALL(mockIpcClient, echo(echoMessage))

View File

@@ -79,7 +79,8 @@ protected:
void readPartialMessage(); void readPartialMessage();
protected: protected:
ClangBackEnd::FileContainer fileContainer{Utf8StringLiteral("foo.cpp"), Utf8String filePath{Utf8StringLiteral("foo.cpp")};
ClangBackEnd::FileContainer fileContainer{filePath,
Utf8StringLiteral("projectPartId"), Utf8StringLiteral("projectPartId"),
Utf8StringLiteral("unsaved content"), Utf8StringLiteral("unsaved content"),
true, true,
@@ -152,7 +153,7 @@ TEST_F(ReadAndWriteMessageBlock, CompareAliveMessage)
TEST_F(ReadAndWriteMessageBlock, CompareRegisterTranslationUnitForEditorMessage) TEST_F(ReadAndWriteMessageBlock, CompareRegisterTranslationUnitForEditorMessage)
{ {
CompareMessage(ClangBackEnd::RegisterTranslationUnitForEditorMessage({fileContainer})); CompareMessage(ClangBackEnd::RegisterTranslationUnitForEditorMessage({fileContainer}, filePath, {filePath}));
} }
TEST_F(ReadAndWriteMessageBlock, CompareUpdateTranslationUnitForEditorMessage) TEST_F(ReadAndWriteMessageBlock, CompareUpdateTranslationUnitForEditorMessage)

View File

@@ -144,6 +144,16 @@ TEST_F(TranslationUnits, Add)
IsTranslationUnit(filePath, projectPartId, 74u)); IsTranslationUnit(filePath, projectPartId, 74u));
} }
TEST_F(TranslationUnits, AddAndTestCreatedTranslationUnit)
{
ClangBackEnd::FileContainer fileContainer(filePath, projectPartId, Utf8StringVector(), 74u);
auto createdTranslationUnits = translationUnits.create({fileContainer});
ASSERT_THAT(createdTranslationUnits.front(),
IsTranslationUnit(filePath, projectPartId, 74u));
}
TEST_F(TranslationUnits, ThrowForCreatingAnExistingTranslationUnit) TEST_F(TranslationUnits, ThrowForCreatingAnExistingTranslationUnit)
{ {
ClangBackEnd::FileContainer fileContainer(filePath, projectPartId, Utf8StringVector(), 74u); ClangBackEnd::FileContainer fileContainer(filePath, projectPartId, Utf8StringVector(), 74u);