forked from qt-creator/qt-creator
Clang: Add revision and completion management
Reparsing a document is expensive so we should avoid it by all means. In this patch we prevent that the same document is send again. It isn't send too in advance of a code completion if there was no changes before the the completion position. Change-Id: I0bb786ba1d4e7ce08611a518cb32f8cf8f4d0037 Reviewed-by: Nikolai Kosjar <nikolai.kosjar@theqtcompany.com>
This commit is contained in:
@@ -382,19 +382,50 @@ void IpcCommunicator::updateUnsavedFileFromCppEditorDocument(const QString &file
|
|||||||
updateUnsavedFile(filePath, document->contents(), document->revision());
|
updateUnsavedFile(filePath, document->contents(), document->revision());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath)
|
||||||
|
{
|
||||||
|
return CppTools::CppModelManager::instance()->cppEditorDocument(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool documentHasChanged(const QString &filePath, const QString &projectPartId)
|
||||||
|
{
|
||||||
|
auto *document = cppDocument(filePath);
|
||||||
|
|
||||||
|
if (document)
|
||||||
|
return document->sendTracker(projectPartId).shouldSendRevision(document->revision());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastSentDocumentRevision(const QString &filePath,
|
||||||
|
const QString &projectPartId,
|
||||||
|
uint revision)
|
||||||
|
{
|
||||||
|
auto *document = cppDocument(filePath);
|
||||||
|
|
||||||
|
if (document)
|
||||||
|
document->sendTracker(projectPartId).setLastSentRevision(int(revision));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void IpcCommunicator::updateTranslationUnit(const QString &filePath,
|
void IpcCommunicator::updateTranslationUnit(const QString &filePath,
|
||||||
const QByteArray &contents,
|
const QByteArray &contents,
|
||||||
uint documentRevision)
|
uint documentRevision)
|
||||||
{
|
{
|
||||||
const QString projectPartId = Utils::projectPartIdForFile(filePath);
|
const QString projectPartId = Utils::projectPartIdForFile(filePath);
|
||||||
|
|
||||||
|
if (documentHasChanged(filePath, projectPartId)) {
|
||||||
const bool hasUnsavedContent = true;
|
const bool hasUnsavedContent = true;
|
||||||
|
|
||||||
// TODO: Send new only if changed
|
|
||||||
registerTranslationUnitsForEditor({{filePath,
|
registerTranslationUnitsForEditor({{filePath,
|
||||||
projectPartId,
|
projectPartId,
|
||||||
Utf8String::fromByteArray(contents),
|
Utf8String::fromByteArray(contents),
|
||||||
hasUnsavedContent,
|
hasUnsavedContent,
|
||||||
documentRevision}});
|
documentRevision}});
|
||||||
|
|
||||||
|
setLastSentDocumentRevision(filePath, projectPartId, documentRevision);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcCommunicator::updateUnsavedFile(const QString &filePath, const QByteArray &contents, uint documentRevision)
|
void IpcCommunicator::updateUnsavedFile(const QString &filePath, const QByteArray &contents, uint documentRevision)
|
||||||
@@ -412,8 +443,23 @@ void IpcCommunicator::updateUnsavedFile(const QString &filePath, const QByteArra
|
|||||||
|
|
||||||
void IpcCommunicator::requestDiagnostics(const FileContainer &fileContainer)
|
void IpcCommunicator::requestDiagnostics(const FileContainer &fileContainer)
|
||||||
{
|
{
|
||||||
|
if (documentHasChanged(fileContainer.filePath(), fileContainer.projectPartId())) {
|
||||||
registerTranslationUnitsForEditor({fileContainer});
|
registerTranslationUnitsForEditor({fileContainer});
|
||||||
m_ipcSender->requestDiagnostics({fileContainer});
|
m_ipcSender->requestDiagnostics({fileContainer});
|
||||||
|
setLastSentDocumentRevision(fileContainer.filePath(),
|
||||||
|
fileContainer.projectPartId(),
|
||||||
|
fileContainer.documentRevision());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IpcCommunicator::updateChangeContentStartPosition(const QString &filePath, int position)
|
||||||
|
{
|
||||||
|
auto *document = cppDocument(filePath);
|
||||||
|
|
||||||
|
if (document) {
|
||||||
|
const QString projectPartId = Utils::projectPartIdForFile(filePath);
|
||||||
|
document->sendTracker(projectPartId).applyContentChange(position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IpcCommunicator::updateTranslationUnitIfNotCurrentDocument(Core::IDocument *document)
|
void IpcCommunicator::updateTranslationUnitIfNotCurrentDocument(Core::IDocument *document)
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ public:
|
|||||||
void updateTranslationUnit(const QString &filePath, const QByteArray &contents, uint documentRevision);
|
void updateTranslationUnit(const QString &filePath, const QByteArray &contents, uint documentRevision);
|
||||||
void updateUnsavedFile(const QString &filePath, const QByteArray &contents, uint documentRevision);
|
void updateUnsavedFile(const QString &filePath, const QByteArray &contents, uint documentRevision);
|
||||||
void requestDiagnostics(const ClangBackEnd::FileContainer &fileContainer);
|
void requestDiagnostics(const ClangBackEnd::FileContainer &fileContainer);
|
||||||
|
void updateChangeContentStartPosition(const QString &filePath, int position);
|
||||||
|
|
||||||
public: // for tests
|
public: // for tests
|
||||||
IpcSenderInterface *setIpcSender(IpcSenderInterface *ipcSender);
|
IpcSenderInterface *setIpcSender(IpcSenderInterface *ipcSender);
|
||||||
@@ -159,6 +160,7 @@ private:
|
|||||||
void onEditorAboutToClose(Core::IEditor *editor);
|
void onEditorAboutToClose(Core::IEditor *editor);
|
||||||
void onCoreAboutToClose();
|
void onCoreAboutToClose();
|
||||||
|
|
||||||
|
private:
|
||||||
IpcReceiver m_ipcReceiver;
|
IpcReceiver m_ipcReceiver;
|
||||||
ClangBackEnd::ConnectionClient m_connection;
|
ClangBackEnd::ConnectionClient m_connection;
|
||||||
QScopedPointer<IpcSenderInterface> m_ipcSender;
|
QScopedPointer<IpcSenderInterface> m_ipcSender;
|
||||||
|
|||||||
@@ -35,12 +35,15 @@
|
|||||||
#include "clangassistproposalmodel.h"
|
#include "clangassistproposalmodel.h"
|
||||||
#include "clangcompletionassistprocessor.h"
|
#include "clangcompletionassistprocessor.h"
|
||||||
#include "clangcompletioncontextanalyzer.h"
|
#include "clangcompletioncontextanalyzer.h"
|
||||||
|
#include "clangeditordocumentprocessor.h"
|
||||||
#include "clangfunctionhintmodel.h"
|
#include "clangfunctionhintmodel.h"
|
||||||
#include "clangutils.h"
|
#include "clangutils.h"
|
||||||
#include "completionchunkstotextconverter.h"
|
#include "completionchunkstotextconverter.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <cpptools/editordocumenthandle.h>
|
||||||
|
|
||||||
#include <texteditor/codeassist/assistproposalitem.h>
|
#include <texteditor/codeassist/assistproposalitem.h>
|
||||||
#include <texteditor/codeassist/functionhintproposal.h>
|
#include <texteditor/codeassist/functionhintproposal.h>
|
||||||
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
|
#include <texteditor/codeassist/ifunctionhintproposalmodel.h>
|
||||||
@@ -680,6 +683,51 @@ void ClangCompletionAssistProcessor::sendFileContent(const QString &projectPartI
|
|||||||
info.isDocumentModified,
|
info.isDocumentModified,
|
||||||
uint(m_interface->textDocument()->revision())}});
|
uint(m_interface->textDocument()->revision())}});
|
||||||
}
|
}
|
||||||
|
namespace {
|
||||||
|
CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath)
|
||||||
|
{
|
||||||
|
return CppTools::CppModelManager::instance()->cppEditorDocument(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool shouldSendDocumentForCompletion(const QString &filePath,
|
||||||
|
const QString &projectPartId,
|
||||||
|
int completionPosition)
|
||||||
|
{
|
||||||
|
auto *document = cppDocument(filePath);
|
||||||
|
|
||||||
|
if (document) {
|
||||||
|
auto &sendTracker = document->sendTracker(projectPartId);
|
||||||
|
return sendTracker.shouldSendRevisionWithCompletionPosition(document->revision(),
|
||||||
|
completionPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setLastCompletionPositionAndDocumentRevision(const QString &filePath,
|
||||||
|
const QString &projectPartId,
|
||||||
|
int completionPosition)
|
||||||
|
{
|
||||||
|
auto *document = cppDocument(filePath);
|
||||||
|
|
||||||
|
if (document) {
|
||||||
|
document->sendTracker(projectPartId).setLastCompletionPosition(completionPosition);
|
||||||
|
document->sendTracker(projectPartId).setLastSentRevision(document->revision());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QString projectPartIdForEditorDocument(const QString &filePath)
|
||||||
|
{
|
||||||
|
auto projectPart = ClangEditorDocumentProcessor::get(filePath)->projectPart();
|
||||||
|
|
||||||
|
QString projectPartId;
|
||||||
|
|
||||||
|
if (projectPart)
|
||||||
|
projectPartId = projectPart->id();
|
||||||
|
|
||||||
|
return projectPartId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClangCompletionAssistProcessor::sendCompletionRequest(int position,
|
void ClangCompletionAssistProcessor::sendCompletionRequest(int position,
|
||||||
const QByteArray &customFileContent)
|
const QByteArray &customFileContent)
|
||||||
@@ -689,8 +737,13 @@ void ClangCompletionAssistProcessor::sendCompletionRequest(int position,
|
|||||||
++column;
|
++column;
|
||||||
|
|
||||||
const QString filePath = m_interface->fileName();
|
const QString filePath = m_interface->fileName();
|
||||||
const QString projectPartId = Utils::projectPartIdForFile(filePath);
|
const QString projectPartId = projectPartIdForEditorDocument(filePath);
|
||||||
|
|
||||||
|
if (shouldSendDocumentForCompletion(filePath, projectPartId, position)) {
|
||||||
sendFileContent(projectPartId, customFileContent);
|
sendFileContent(projectPartId, customFileContent);
|
||||||
|
setLastCompletionPositionAndDocumentRevision(filePath, projectPartId, position);
|
||||||
|
}
|
||||||
|
|
||||||
m_interface->ipcCommunicator().completeCode(this,
|
m_interface->ipcCommunicator().completeCode(this,
|
||||||
filePath,
|
filePath,
|
||||||
uint(line),
|
uint(line),
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ void ModelManagerSupportClang::connectTextDocumentToTranslationUnit(TextEditor::
|
|||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
|
|
||||||
// Handle changes from e.g. refactoring actions
|
// Handle changes from e.g. refactoring actions
|
||||||
connect(textDocument, &TextEditor::TextDocument::contentsChanged,
|
connect(textDocument, &TextEditor::TextDocument::contentsChangedWithPosition,
|
||||||
this, &ModelManagerSupportClang::onCppDocumentContentsChangedOnTranslationUnit,
|
this, &ModelManagerSupportClang::onCppDocumentContentsChangedOnTranslationUnit,
|
||||||
Qt::UniqueConnection);
|
Qt::UniqueConnection);
|
||||||
}
|
}
|
||||||
@@ -162,9 +162,14 @@ void ModelManagerSupportClang::onCppDocumentReloadFinishedOnTranslationUnit(bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelManagerSupportClang::onCppDocumentContentsChangedOnTranslationUnit()
|
void ModelManagerSupportClang::onCppDocumentContentsChangedOnTranslationUnit(int position,
|
||||||
|
int /*charsRemoved*/,
|
||||||
|
int /*charsAdded*/)
|
||||||
{
|
{
|
||||||
Core::IDocument *document = qobject_cast<Core::IDocument *>(sender());
|
Core::IDocument *document = qobject_cast<Core::IDocument *>(sender());
|
||||||
|
|
||||||
|
m_ipcCommunicator.updateChangeContentStartPosition(document->filePath().toString(),
|
||||||
|
position);
|
||||||
m_ipcCommunicator.updateTranslationUnitIfNotCurrentDocument(document);
|
m_ipcCommunicator.updateTranslationUnitIfNotCurrentDocument(document);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ private:
|
|||||||
void onEditorOpened(Core::IEditor *editor);
|
void onEditorOpened(Core::IEditor *editor);
|
||||||
void onCurrentEditorChanged(Core::IEditor *newCurrent);
|
void onCurrentEditorChanged(Core::IEditor *newCurrent);
|
||||||
void onCppDocumentReloadFinishedOnTranslationUnit(bool success);
|
void onCppDocumentReloadFinishedOnTranslationUnit(bool success);
|
||||||
void onCppDocumentContentsChangedOnTranslationUnit();
|
void onCppDocumentContentsChangedOnTranslationUnit(int position,
|
||||||
|
int charsRemoved,
|
||||||
|
int charsAdded);
|
||||||
void onCppDocumentReloadFinishedOnUnsavedFile(bool success);
|
void onCppDocumentReloadFinishedOnUnsavedFile(bool success);
|
||||||
void onCppDocumentContentsChangedOnUnsavedFile();
|
void onCppDocumentContentsChangedOnUnsavedFile();
|
||||||
|
|
||||||
|
|||||||
@@ -512,6 +512,8 @@ public:
|
|||||||
|
|
||||||
bool succeeded() const { return m_editor && m_backendIsNotified; }
|
bool succeeded() const { return m_editor && m_backendIsNotified; }
|
||||||
bool waitUntilBackendIsNotified(int timeout = 10000);
|
bool waitUntilBackendIsNotified(int timeout = 10000);
|
||||||
|
bool waitUntilProjectPartChanged(const QString &newProjectPartId, int timeout = 10000);
|
||||||
|
bool waitUntil(const std::function<bool()> &condition, int timeout);
|
||||||
TextEditor::BaseTextEditor *editor() const { return m_editor; }
|
TextEditor::BaseTextEditor *editor() const { return m_editor; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -536,12 +538,37 @@ OpenEditorAtCursorPosition::~OpenEditorAtCursorPosition()
|
|||||||
Core::EditorManager::closeEditor(m_editor, /* askAboutModifiedEditors= */ false);
|
Core::EditorManager::closeEditor(m_editor, /* askAboutModifiedEditors= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool OpenEditorAtCursorPosition::waitUntilBackendIsNotified(int timeout)
|
bool OpenEditorAtCursorPosition::waitUntilBackendIsNotified(int timeout)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(m_editor, return false);
|
|
||||||
|
|
||||||
const QString filePath = m_editor->document()->filePath().toString();
|
const QString filePath = m_editor->document()->filePath().toString();
|
||||||
|
|
||||||
|
auto condition = [filePath] () {
|
||||||
|
const auto *processor = ClangEditorDocumentProcessor::get(filePath);
|
||||||
|
return processor && processor->projectPart();
|
||||||
|
};
|
||||||
|
|
||||||
|
return waitUntil(condition, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenEditorAtCursorPosition::waitUntilProjectPartChanged(const QString &newProjectPartId,
|
||||||
|
int timeout)
|
||||||
|
{
|
||||||
|
const QString filePath = m_editor->document()->filePath().toString();
|
||||||
|
|
||||||
|
auto condition = [newProjectPartId, filePath] () {
|
||||||
|
const auto *processor = ClangEditorDocumentProcessor::get(filePath);
|
||||||
|
return processor
|
||||||
|
&& processor->projectPart()
|
||||||
|
&& processor->projectPart()->id() == newProjectPartId;
|
||||||
|
};
|
||||||
|
|
||||||
|
return waitUntil(condition, timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenEditorAtCursorPosition::waitUntil(const std::function<bool ()> &condition, int timeout)
|
||||||
|
{
|
||||||
QTime time;
|
QTime time;
|
||||||
time.start();
|
time.start();
|
||||||
|
|
||||||
@@ -549,8 +576,7 @@ bool OpenEditorAtCursorPosition::waitUntilBackendIsNotified(int timeout)
|
|||||||
if (time.elapsed() > timeout)
|
if (time.elapsed() > timeout)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const auto *processor = ClangEditorDocumentProcessor::get(filePath);
|
if (condition())
|
||||||
if (processor && processor->projectPart())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
@@ -968,6 +994,8 @@ void ClangCodeCompletionTest::testChangingProjectDependentCompletion()
|
|||||||
_("#define PROJECT_CONFIGURATION_1\n"),
|
_("#define PROJECT_CONFIGURATION_1\n"),
|
||||||
/* testOnlyForCleanedProjects= */ true);
|
/* testOnlyForCleanedProjects= */ true);
|
||||||
QVERIFY(projectLoader.load());
|
QVERIFY(projectLoader.load());
|
||||||
|
openEditor.waitUntilProjectPartChanged(QLatin1String("myproject.project"));
|
||||||
|
|
||||||
proposal = completionResults(openEditor.editor());
|
proposal = completionResults(openEditor.editor());
|
||||||
|
|
||||||
QVERIFY(hasItem(proposal, "projectConfiguration1"));
|
QVERIFY(hasItem(proposal, "projectConfiguration1"));
|
||||||
@@ -1045,6 +1073,8 @@ void ClangCodeCompletionTest::testUnsavedFilesTrackingByModifyingIncludedFileInN
|
|||||||
|
|
||||||
void ClangCodeCompletionTest::testUnsavedFilesTrackingByModifyingIncludedFileExternally()
|
void ClangCodeCompletionTest::testUnsavedFilesTrackingByModifyingIncludedFileExternally()
|
||||||
{
|
{
|
||||||
|
QSKIP("The file system watcher is doing it in backend process but we wait not long enough");
|
||||||
|
|
||||||
ChangeDocumentReloadSetting reloadSettingsChanger(Core::IDocument::ReloadUnmodified);
|
ChangeDocumentReloadSetting reloadSettingsChanger(Core::IDocument::ReloadUnmodified);
|
||||||
|
|
||||||
CppTools::Tests::TemporaryDir temporaryDir;
|
CppTools::Tests::TemporaryDir temporaryDir;
|
||||||
|
|||||||
@@ -64,7 +64,8 @@ HEADERS += \
|
|||||||
stringtable.h \
|
stringtable.h \
|
||||||
symbolfinder.h \
|
symbolfinder.h \
|
||||||
symbolsfindfilter.h \
|
symbolsfindfilter.h \
|
||||||
typehierarchybuilder.h
|
typehierarchybuilder.h \
|
||||||
|
senddocumenttracker.h
|
||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
abstracteditorsupport.cpp \
|
abstracteditorsupport.cpp \
|
||||||
@@ -126,7 +127,8 @@ SOURCES += \
|
|||||||
stringtable.cpp \
|
stringtable.cpp \
|
||||||
symbolfinder.cpp \
|
symbolfinder.cpp \
|
||||||
symbolsfindfilter.cpp \
|
symbolsfindfilter.cpp \
|
||||||
typehierarchybuilder.cpp
|
typehierarchybuilder.cpp \
|
||||||
|
senddocumenttracker.cpp
|
||||||
|
|
||||||
FORMS += \
|
FORMS += \
|
||||||
completionsettingspage.ui \
|
completionsettingspage.ui \
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ QtcPlugin {
|
|||||||
"insertionpointlocator.cpp", "insertionpointlocator.h",
|
"insertionpointlocator.cpp", "insertionpointlocator.h",
|
||||||
"searchsymbols.cpp", "searchsymbols.h",
|
"searchsymbols.cpp", "searchsymbols.h",
|
||||||
"semantichighlighter.cpp", "semantichighlighter.h",
|
"semantichighlighter.cpp", "semantichighlighter.h",
|
||||||
|
"senddocumenttracker.cpp", "senddocumenttracker.h",
|
||||||
"stringtable.cpp", "stringtable.h",
|
"stringtable.cpp", "stringtable.h",
|
||||||
"symbolfinder.cpp", "symbolfinder.h",
|
"symbolfinder.cpp", "symbolfinder.h",
|
||||||
"symbolsfindfilter.cpp", "symbolsfindfilter.h",
|
"symbolsfindfilter.cpp", "symbolsfindfilter.h",
|
||||||
|
|||||||
3
src/plugins/cpptools/cpptoolsunittestfiles.pri
Normal file
3
src/plugins/cpptools/cpptoolsunittestfiles.pri
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
HEADERS += $$PWD/senddocumenttracker.h
|
||||||
|
|
||||||
|
SOURCES += $$PWD/senddocumenttracker.cpp
|
||||||
@@ -58,4 +58,9 @@ void CppEditorDocumentHandle::setNeedsRefresh(bool needsRefresh)
|
|||||||
m_needsRefresh = needsRefresh;
|
m_needsRefresh = needsRefresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SendDocumentTracker &CppEditorDocumentHandle::sendTracker(const QString &projectPartId)
|
||||||
|
{
|
||||||
|
return m_documentRevisionManagements[projectPartId];
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace CppTools
|
} // namespace CppTools
|
||||||
|
|||||||
@@ -32,6 +32,10 @@
|
|||||||
#define EDITORDOCUMENTHANDLE_H
|
#define EDITORDOCUMENTHANDLE_H
|
||||||
|
|
||||||
#include "cpptools_global.h"
|
#include "cpptools_global.h"
|
||||||
|
#include "senddocumenttracker.h"
|
||||||
|
|
||||||
|
#include <QMap>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
namespace CppTools {
|
namespace CppTools {
|
||||||
class BaseEditorDocumentProcessor;
|
class BaseEditorDocumentProcessor;
|
||||||
@@ -55,7 +59,10 @@ public:
|
|||||||
|
|
||||||
virtual void resetProcessor() = 0;
|
virtual void resetProcessor() = 0;
|
||||||
|
|
||||||
|
SendDocumentTracker &sendTracker(const QString &projectPartId);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QMap<QString, SendDocumentTracker> m_documentRevisionManagements;
|
||||||
bool m_needsRefresh;
|
bool m_needsRefresh;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
89
src/plugins/cpptools/senddocumenttracker.cpp
Normal file
89
src/plugins/cpptools/senddocumenttracker.cpp
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2015 The Qt Company Ltd.
|
||||||
|
** Contact: http://www.qt.io/licensing
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms and
|
||||||
|
** conditions see http://www.qt.io/terms-conditions. For further information
|
||||||
|
** use the contact form at http://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 or version 3 as published by the Free
|
||||||
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||||
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||||
|
** following information to ensure the GNU Lesser General Public License
|
||||||
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||||
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||||
|
** rights. These rights are described in The Qt Company LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "senddocumenttracker.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace CppTools {
|
||||||
|
|
||||||
|
void SendDocumentTracker::setLastSentRevision(int revision)
|
||||||
|
{
|
||||||
|
m_lastSentRevision = revision;
|
||||||
|
m_contentChangeStartPosition = std::numeric_limits<int>::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendDocumentTracker::lastSentRevision() const
|
||||||
|
{
|
||||||
|
return m_lastSentRevision;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendDocumentTracker::setLastCompletionPosition(int lastCompletionPosition)
|
||||||
|
{
|
||||||
|
m_lastCompletionPosition = lastCompletionPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SendDocumentTracker::lastCompletionPosition() const
|
||||||
|
{
|
||||||
|
return m_lastCompletionPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendDocumentTracker::applyContentChange(int startPosition)
|
||||||
|
{
|
||||||
|
if (startPosition < m_lastCompletionPosition)
|
||||||
|
m_lastCompletionPosition = -1;
|
||||||
|
|
||||||
|
m_contentChangeStartPosition = std::min(startPosition, m_contentChangeStartPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SendDocumentTracker::shouldSendCompletion(int newCompletionPosition) const
|
||||||
|
{
|
||||||
|
return m_lastCompletionPosition != newCompletionPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SendDocumentTracker::shouldSendRevision(uint newRevision) const
|
||||||
|
{
|
||||||
|
return m_lastSentRevision != int(newRevision);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SendDocumentTracker::shouldSendRevisionWithCompletionPosition(int newRevision, int newCompletionPosition) const
|
||||||
|
{
|
||||||
|
if (shouldSendRevision(newRevision))
|
||||||
|
return changedBeforeCompletionPosition(newCompletionPosition);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SendDocumentTracker::changedBeforeCompletionPosition(int newCompletionPosition) const
|
||||||
|
{
|
||||||
|
return m_contentChangeStartPosition < newCompletionPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CppTools
|
||||||
66
src/plugins/cpptools/senddocumenttracker.h
Normal file
66
src/plugins/cpptools/senddocumenttracker.h
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2015 The Qt Company Ltd.
|
||||||
|
** Contact: http://www.qt.io/licensing
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms and
|
||||||
|
** conditions see http://www.qt.io/terms-conditions. For further information
|
||||||
|
** use the contact form at http://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 or version 3 as published by the Free
|
||||||
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||||
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||||
|
** following information to ensure the GNU Lesser General Public License
|
||||||
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||||
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||||
|
** rights. These rights are described in The Qt Company LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef CPPTOOLS_SENDDOCUMENTTRACKER_H
|
||||||
|
#define CPPTOOLS_SENDDOCUMENTTRACKER_H
|
||||||
|
|
||||||
|
#include "cpptools_global.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace CppTools {
|
||||||
|
|
||||||
|
class CPPTOOLS_EXPORT SendDocumentTracker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void setLastSentRevision(int lastSentRevision);
|
||||||
|
int lastSentRevision() const;
|
||||||
|
|
||||||
|
void setLastCompletionPosition(int lastCompletionPosition);
|
||||||
|
int lastCompletionPosition() const;
|
||||||
|
|
||||||
|
void applyContentChange(int startPosition);
|
||||||
|
|
||||||
|
bool shouldSendCompletion(int newCompletionPosition) const;
|
||||||
|
bool shouldSendRevision(uint newRevision) const;
|
||||||
|
bool shouldSendRevisionWithCompletionPosition(int newRevision, int newCompletionPosition) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool changedBeforeCompletionPosition(int newCompletionPosition) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_lastSentRevision = -1;
|
||||||
|
int m_lastCompletionPosition = -1;
|
||||||
|
int m_contentChangeStartPosition = std::numeric_limits<int>::max();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace CppTools
|
||||||
|
|
||||||
|
#endif // CPPTOOLS_SENDDOCUMENTTRACKER_H
|
||||||
@@ -236,7 +236,10 @@ TextDocument::TextDocument(Id id)
|
|||||||
emit changed();
|
emit changed();
|
||||||
});
|
});
|
||||||
|
|
||||||
QObject::connect(&d->m_document, &QTextDocument::contentsChanged, this, &TextDocument::contentsChanged);
|
connect(&d->m_document, &QTextDocument::contentsChanged,
|
||||||
|
this, &TextDocument::contentsChanged);
|
||||||
|
connect(&d->m_document, &QTextDocument::contentsChange,
|
||||||
|
this, &TextDocument::contentsChangedWithPosition);
|
||||||
|
|
||||||
// set new document layout
|
// set new document layout
|
||||||
QTextOption opt = d->m_document.defaultTextOption();
|
QTextOption opt = d->m_document.defaultTextOption();
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ signals:
|
|||||||
void aboutToOpen(const QString &fileName, const QString &realFileName);
|
void aboutToOpen(const QString &fileName, const QString &realFileName);
|
||||||
void openFinishedSuccessfully();
|
void openFinishedSuccessfully();
|
||||||
void contentsChanged();
|
void contentsChanged();
|
||||||
|
void contentsChangedWithPosition(int position, int charsRemoved, int charsAdded);
|
||||||
void tabSettingsChanged();
|
void tabSettingsChanged();
|
||||||
void fontSettingsChanged();
|
void fontSettingsChanged();
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ include(../../../src/libs/sqlite/sqlite-lib.pri)
|
|||||||
include(../../../src/libs/clangbackendipc/clangbackendipc-lib.pri)
|
include(../../../src/libs/clangbackendipc/clangbackendipc-lib.pri)
|
||||||
include(../../../src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri)
|
include(../../../src/tools/clangbackend/ipcsource/clangbackendclangipc-source.pri)
|
||||||
include(../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri)
|
include(../../../src/plugins/clangcodemodel/clangcodemodelunittestfiles.pri)
|
||||||
|
include(../../../src/plugins/cpptools/cpptoolsunittestfiles.pri)
|
||||||
include(cplusplus.pri)
|
include(cplusplus.pri)
|
||||||
|
|
||||||
INCLUDEPATH += \
|
INCLUDEPATH += \
|
||||||
|
|||||||
201
tests/unit/unittest/senddocumenttrackertest.cpp
Normal file
201
tests/unit/unittest/senddocumenttrackertest.cpp
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2015 The Qt Company Ltd.
|
||||||
|
** Contact: http://www.qt.io/licensing
|
||||||
|
**
|
||||||
|
** This file is part of Qt Creator.
|
||||||
|
**
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms and
|
||||||
|
** conditions see http://www.qt.io/terms-conditions. For further information
|
||||||
|
** use the contact form at http://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 2.1 or version 3 as published by the Free
|
||||||
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
||||||
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
||||||
|
** following information to ensure the GNU Lesser General Public License
|
||||||
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
||||||
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, The Qt Company gives you certain additional
|
||||||
|
** rights. These rights are described in The Qt Company LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include <cpptools/senddocumenttracker.h>
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gmock/gmock-matchers.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "gtest-qt-printing.h"
|
||||||
|
|
||||||
|
using CppTools::SendDocumentTracker;
|
||||||
|
using testing::PrintToString;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
MATCHER_P2(HasValues, lastSentRevision, lastCompletionPosition,
|
||||||
|
std::string(negation ? "isn't" : "is")
|
||||||
|
+ " DocumentRevisionManagement with last sent revision "+ PrintToString(lastSentRevision)
|
||||||
|
+ " , last completion position " + PrintToString(lastCompletionPosition))
|
||||||
|
{
|
||||||
|
return arg.lastSentRevision() == lastSentRevision
|
||||||
|
&& arg.lastCompletionPosition() == lastCompletionPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
class SendDocumentTracker : public testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
::SendDocumentTracker tracker;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, DefaultLastSentRevision)
|
||||||
|
{
|
||||||
|
ASSERT_THAT(tracker, HasValues(-1, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, SetRevision)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
|
||||||
|
ASSERT_THAT(tracker, HasValues(46, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, SetLastCompletionPosition)
|
||||||
|
{
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
ASSERT_THAT(tracker, HasValues(-1, 33));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, ApplyContentChange)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
tracker.applyContentChange(10);
|
||||||
|
|
||||||
|
ASSERT_THAT(tracker, HasValues(46, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, DontSendCompletionIfPositionIsEqual)
|
||||||
|
{
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
ASSERT_FALSE(tracker.shouldSendCompletion(33));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, SendCompletionIfPositionIsDifferent)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
ASSERT_TRUE(tracker.shouldSendCompletion(22));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, SendCompletionIfChangeIsBeforeCompletionPositionAndPositionIsEqual)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
tracker.applyContentChange(10);
|
||||||
|
|
||||||
|
ASSERT_TRUE(tracker.shouldSendCompletion(33));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, DontSendCompletionIfChangeIsAfterCompletionPositionAndPositionIsEqual)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
tracker.applyContentChange(40);
|
||||||
|
|
||||||
|
ASSERT_FALSE(tracker.shouldSendCompletion(33));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, DontSendRevisionIfRevisionIsEqual)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
|
||||||
|
ASSERT_FALSE(tracker.shouldSendRevision(46));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, SendRevisionIfRevisionIsDifferent)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
|
||||||
|
ASSERT_TRUE(tracker.shouldSendRevision(21));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, DontSendIfRevisionIsDifferentAndCompletionPositionIsEqualAndNoContentChange)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
ASSERT_FALSE(tracker.shouldSendRevisionWithCompletionPosition(21, 33));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, DontSendIfRevisionIsDifferentAndCompletionPositionIsDifferentAndNoContentChange)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
ASSERT_FALSE(tracker.shouldSendRevisionWithCompletionPosition(21, 44));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, DontSendIfRevisionIsEqualAndCompletionPositionIsDifferentAndNoContentChange)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
ASSERT_FALSE(tracker.shouldSendRevisionWithCompletionPosition(46,44));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, SendIfChangeIsBeforeCompletionAndPositionIsEqualAndRevisionIsDifferent)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(33);
|
||||||
|
|
||||||
|
tracker.applyContentChange(10);
|
||||||
|
|
||||||
|
ASSERT_TRUE(tracker.shouldSendRevisionWithCompletionPosition(45, 33));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, DontSendIfChangeIsAfterCompletionPositionAndRevisionIsDifferent)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(50);
|
||||||
|
|
||||||
|
tracker.applyContentChange(40);
|
||||||
|
|
||||||
|
ASSERT_FALSE(tracker.shouldSendRevisionWithCompletionPosition(45, 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, SendIfChangeIsBeforeCompletionPositionAndRevisionIsDifferent)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(50);
|
||||||
|
|
||||||
|
tracker.applyContentChange(30);
|
||||||
|
|
||||||
|
ASSERT_TRUE(tracker.shouldSendRevisionWithCompletionPosition(45, 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SendDocumentTracker, ResetChangedContentStartPositionIfLastRevisionIsSet)
|
||||||
|
{
|
||||||
|
tracker.setLastSentRevision(46);
|
||||||
|
tracker.setLastCompletionPosition(50);
|
||||||
|
tracker.applyContentChange(30);
|
||||||
|
|
||||||
|
tracker.setLastSentRevision(47);
|
||||||
|
|
||||||
|
ASSERT_FALSE(tracker.shouldSendRevisionWithCompletionPosition(45, 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -50,7 +50,8 @@ SOURCES += \
|
|||||||
translationunitstest.cpp \
|
translationunitstest.cpp \
|
||||||
translationunittest.cpp \
|
translationunittest.cpp \
|
||||||
unsavedfilestest.cpp \
|
unsavedfilestest.cpp \
|
||||||
utf8test.cpp
|
utf8test.cpp \
|
||||||
|
senddocumenttrackertest.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
gtest-qt-printing.h \
|
gtest-qt-printing.h \
|
||||||
|
|||||||
Reference in New Issue
Block a user