forked from qt-creator/qt-creator
CppTools: Remove separate indexing revision
For indexing we used a custom revision that was updated on each modelManager BuiltinIndexingSupport::refreshSourceFiles() call. This could lead to rejection of updated documents triggered by refactoring actions, like for the following case: 1. Open a project containing a.h and a.cpp 2. Open a.cpp, insert some new lines, save and close the document 3. Open a.h and rename a function that is defined in a.cpp --> The refactoring action modifies a.h and a.cpp, so re-indexing of those is triggered. Since a.cpp has already a higher revision (step 2) than the updated document, the updated document is discarded. As a consequence find usages and follow symbol fails for the renamed function. Now the document call back provided to CppSourceProcessor is responsible for updating the document revision based on the latest revision in the global snapshot. Change-Id: I4dfa0a4d34991655acfa749109f00c47b0fbfdbe Reviewed-by: Orgad Shaneh <orgads@gmail.com> Reviewed-by: Erik Verbruggen <erik.verbruggen@theqtcompany.com> Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com>
This commit is contained in:
@@ -61,9 +61,6 @@ namespace {
|
|||||||
class ParseParams
|
class ParseParams
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ParseParams() : revision(0) {}
|
|
||||||
|
|
||||||
int revision;
|
|
||||||
ProjectPart::HeaderPaths headerPaths;
|
ProjectPart::HeaderPaths headerPaths;
|
||||||
WorkingCopy workingCopy;
|
WorkingCopy workingCopy;
|
||||||
QSet<QString> sourceFiles;
|
QSet<QString> sourceFiles;
|
||||||
@@ -189,7 +186,6 @@ void indexFindErrors(QFutureInterface<void> &future, const ParseParams params)
|
|||||||
void index(QFutureInterface<void> &future, const ParseParams params)
|
void index(QFutureInterface<void> &future, const ParseParams params)
|
||||||
{
|
{
|
||||||
QScopedPointer<CppSourceProcessor> sourceProcessor(CppModelManager::createSourceProcessor());
|
QScopedPointer<CppSourceProcessor> sourceProcessor(CppModelManager::createSourceProcessor());
|
||||||
sourceProcessor->setRevision(params.revision);
|
|
||||||
sourceProcessor->setHeaderPaths(params.headerPaths);
|
sourceProcessor->setHeaderPaths(params.headerPaths);
|
||||||
sourceProcessor->setWorkingCopy(params.workingCopy);
|
sourceProcessor->setWorkingCopy(params.workingCopy);
|
||||||
|
|
||||||
@@ -347,7 +343,6 @@ private:
|
|||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
BuiltinIndexingSupport::BuiltinIndexingSupport()
|
BuiltinIndexingSupport::BuiltinIndexingSupport()
|
||||||
: m_revision(0)
|
|
||||||
{
|
{
|
||||||
m_synchronizer.setCancelOnWait(true);
|
m_synchronizer.setCancelOnWait(true);
|
||||||
}
|
}
|
||||||
@@ -361,7 +356,6 @@ QFuture<void> BuiltinIndexingSupport::refreshSourceFiles(const QSet<QString> &so
|
|||||||
CppModelManager *mgr = CppModelManager::instance();
|
CppModelManager *mgr = CppModelManager::instance();
|
||||||
|
|
||||||
ParseParams params;
|
ParseParams params;
|
||||||
params.revision = ++m_revision;
|
|
||||||
params.headerPaths = mgr->headerPaths();
|
params.headerPaths = mgr->headerPaths();
|
||||||
params.workingCopy = mgr->workingCopy();
|
params.workingCopy = mgr->workingCopy();
|
||||||
params.sourceFiles = sourceFiles;
|
params.sourceFiles = sourceFiles;
|
||||||
|
@@ -54,7 +54,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QFutureSynchronizer<void> m_synchronizer;
|
QFutureSynchronizer<void> m_synchronizer;
|
||||||
unsigned m_revision;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
@@ -232,6 +232,11 @@ CppSourceProcessor *CppModelManager::createSourceProcessor()
|
|||||||
{
|
{
|
||||||
CppModelManager *that = instance();
|
CppModelManager *that = instance();
|
||||||
return new CppSourceProcessor(that->snapshot(), [that](const Document::Ptr &doc) {
|
return new CppSourceProcessor(that->snapshot(), [that](const Document::Ptr &doc) {
|
||||||
|
const Document::Ptr previousDocument = that->document(doc->fileName());
|
||||||
|
const unsigned newRevision = previousDocument.isNull()
|
||||||
|
? 1U
|
||||||
|
: previousDocument->revision() + 1;
|
||||||
|
doc->setRevision(newRevision);
|
||||||
that->emitDocumentUpdated(doc);
|
that->emitDocumentUpdated(doc);
|
||||||
doc->releaseSourceAndAST();
|
doc->releaseSourceAndAST();
|
||||||
});
|
});
|
||||||
|
@@ -48,6 +48,10 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
|
|
||||||
|
#define VERIFY_DOCUMENT_REVISION(document, expectedRevision) \
|
||||||
|
QVERIFY(document); \
|
||||||
|
QCOMPARE(document->revision(), expectedRevision);
|
||||||
|
|
||||||
using namespace CppTools;
|
using namespace CppTools;
|
||||||
using namespace CppTools::Internal;
|
using namespace CppTools::Internal;
|
||||||
using namespace CppTools::Tests;
|
using namespace CppTools::Tests;
|
||||||
@@ -172,6 +176,15 @@ static QSet<QString> updateProjectInfo(CppModelManager *modelManager, ModelManag
|
|||||||
return helper->waitForRefreshedSourceFiles();
|
return helper->waitForRefreshedSourceFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void waitForProcessedEditorDocument(const QString &filePath)
|
||||||
|
{
|
||||||
|
CppEditorDocumentHandle *editorDocument
|
||||||
|
= CppModelManager::instance()->cppEditorDocument(filePath);
|
||||||
|
QVERIFY(editorDocument);
|
||||||
|
while (editorDocument->processor()->isParserRunning())
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
/// Check: The preprocessor cleans include and framework paths.
|
/// Check: The preprocessor cleans include and framework paths.
|
||||||
@@ -1107,3 +1120,45 @@ void CppToolsPlugin::test_modelmanager_renameIncludes()
|
|||||||
foreach (const QString &sourceFile, sourceFiles)
|
foreach (const QString &sourceFile, sourceFiles)
|
||||||
QCOMPARE(snapshot.allIncludesForDocument(sourceFile), QSet<QString>() << newHeader);
|
QCOMPARE(snapshot.allIncludesForDocument(sourceFile), QSet<QString>() << newHeader);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CppToolsPlugin::test_modelmanager_documentsAndRevisions()
|
||||||
|
{
|
||||||
|
TestCase helper;
|
||||||
|
|
||||||
|
// Index two files
|
||||||
|
const MyTestDataDir testDir(_("testdata_project1"));
|
||||||
|
const QString filePath1 = testDir.file(QLatin1String("foo.h"));
|
||||||
|
const QString filePath2 = testDir.file(QLatin1String("foo.cpp"));
|
||||||
|
const QSet<QString> filesToIndex = QSet<QString>() << filePath1 << filePath2;
|
||||||
|
QVERIFY(TestCase::parseFiles(filesToIndex));
|
||||||
|
|
||||||
|
CppModelManager *modelManager = CppModelManager::instance();
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath1), 1U);
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath2), 1U);
|
||||||
|
|
||||||
|
// Open editor for file 1
|
||||||
|
TextEditor::BaseTextEditor *editor1;
|
||||||
|
QVERIFY(helper.openBaseTextEditor(filePath1, &editor1));
|
||||||
|
helper.closeEditorAtEndOfTestCase(editor1);
|
||||||
|
waitForProcessedEditorDocument(filePath1);
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath1), 2U);
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath2), 1U);
|
||||||
|
|
||||||
|
// Index again
|
||||||
|
QVERIFY(TestCase::parseFiles(filesToIndex));
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath1), 3U);
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath2), 2U);
|
||||||
|
|
||||||
|
// Open editor for file 2
|
||||||
|
TextEditor::BaseTextEditor *editor2;
|
||||||
|
QVERIFY(helper.openBaseTextEditor(filePath2, &editor2));
|
||||||
|
helper.closeEditorAtEndOfTestCase(editor2);
|
||||||
|
waitForProcessedEditorDocument(filePath2);
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath1), 3U);
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath2), 3U);
|
||||||
|
|
||||||
|
// Index again
|
||||||
|
QVERIFY(TestCase::parseFiles(filesToIndex));
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath1), 4U);
|
||||||
|
VERIFY_DOCUMENT_REVISION(modelManager->document(filePath2), 4U);
|
||||||
|
}
|
||||||
|
@@ -117,7 +117,6 @@ CppSourceProcessor::CppSourceProcessor(const Snapshot &snapshot, DocumentCallbac
|
|||||||
m_documentFinished(documentFinished),
|
m_documentFinished(documentFinished),
|
||||||
m_preprocess(this, &m_env),
|
m_preprocess(this, &m_env),
|
||||||
m_languageFeatures(LanguageFeatures::defaultFeatures()),
|
m_languageFeatures(LanguageFeatures::defaultFeatures()),
|
||||||
m_revision(0),
|
|
||||||
m_defaultCodec(Core::EditorManager::defaultTextCodec())
|
m_defaultCodec(Core::EditorManager::defaultTextCodec())
|
||||||
{
|
{
|
||||||
m_preprocess.setKeepComments(true);
|
m_preprocess.setKeepComments(true);
|
||||||
@@ -126,9 +125,6 @@ CppSourceProcessor::CppSourceProcessor(const Snapshot &snapshot, DocumentCallbac
|
|||||||
CppSourceProcessor::~CppSourceProcessor()
|
CppSourceProcessor::~CppSourceProcessor()
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void CppSourceProcessor::setRevision(unsigned revision)
|
|
||||||
{ m_revision = revision; }
|
|
||||||
|
|
||||||
void CppSourceProcessor::setWorkingCopy(const WorkingCopy &workingCopy)
|
void CppSourceProcessor::setWorkingCopy(const WorkingCopy &workingCopy)
|
||||||
{ m_workingCopy = workingCopy; }
|
{ m_workingCopy = workingCopy; }
|
||||||
|
|
||||||
@@ -470,7 +466,6 @@ void CppSourceProcessor::sourceNeeded(unsigned line, const QString &fileName, In
|
|||||||
qCDebug(log) << "Parsing:" << absoluteFileName << "contents:" << contents.size() << "bytes";
|
qCDebug(log) << "Parsing:" << absoluteFileName << "contents:" << contents.size() << "bytes";
|
||||||
|
|
||||||
Document::Ptr document = Document::create(absoluteFileName);
|
Document::Ptr document = Document::create(absoluteFileName);
|
||||||
document->setRevision(m_revision);
|
|
||||||
document->setEditorRevision(editorRevision);
|
document->setEditorRevision(editorRevision);
|
||||||
document->setLanguageFeatures(m_languageFeatures);
|
document->setLanguageFeatures(m_languageFeatures);
|
||||||
foreach (const QString &include, initialIncludes) {
|
foreach (const QString &include, initialIncludes) {
|
||||||
|
@@ -65,7 +65,6 @@ public:
|
|||||||
CppSourceProcessor(const CPlusPlus::Snapshot &snapshot, DocumentCallback documentFinished);
|
CppSourceProcessor(const CPlusPlus::Snapshot &snapshot, DocumentCallback documentFinished);
|
||||||
~CppSourceProcessor();
|
~CppSourceProcessor();
|
||||||
|
|
||||||
void setRevision(unsigned revision);
|
|
||||||
void setWorkingCopy(const CppTools::WorkingCopy &workingCopy);
|
void setWorkingCopy(const CppTools::WorkingCopy &workingCopy);
|
||||||
void setHeaderPaths(const ProjectPart::HeaderPaths &headerPaths);
|
void setHeaderPaths(const ProjectPart::HeaderPaths &headerPaths);
|
||||||
void setLanguageFeatures(CPlusPlus::LanguageFeatures languageFeatures);
|
void setLanguageFeatures(CPlusPlus::LanguageFeatures languageFeatures);
|
||||||
@@ -124,7 +123,6 @@ private:
|
|||||||
CPlusPlus::Document::Ptr m_currentDoc;
|
CPlusPlus::Document::Ptr m_currentDoc;
|
||||||
QSet<QString> m_todo;
|
QSet<QString> m_todo;
|
||||||
QSet<QString> m_processed;
|
QSet<QString> m_processed;
|
||||||
unsigned m_revision;
|
|
||||||
QHash<QString, QString> m_fileNameCache;
|
QHash<QString, QString> m_fileNameCache;
|
||||||
QTextCodec *m_defaultCodec;
|
QTextCodec *m_defaultCodec;
|
||||||
};
|
};
|
||||||
|
@@ -158,6 +158,7 @@ private slots:
|
|||||||
void test_modelmanager_updateEditorsAfterProjectUpdate();
|
void test_modelmanager_updateEditorsAfterProjectUpdate();
|
||||||
void test_modelmanager_precompiled_headers();
|
void test_modelmanager_precompiled_headers();
|
||||||
void test_modelmanager_renameIncludes();
|
void test_modelmanager_renameIncludes();
|
||||||
|
void test_modelmanager_documentsAndRevisions();
|
||||||
|
|
||||||
void test_cpplocatorfilters_CppLocatorFilter();
|
void test_cpplocatorfilters_CppLocatorFilter();
|
||||||
void test_cpplocatorfilters_CppLocatorFilter_data();
|
void test_cpplocatorfilters_CppLocatorFilter_data();
|
||||||
|
Reference in New Issue
Block a user