forked from qt-creator/qt-creator
Clang: Minimize reindexing
We optimal indexer is only reindexing if the index would be changed. This patch is a step in that direction. We only reindex now if the file or project has changed. It fixes some typos too. Task-number: QTCREATORBUG-21150 Change-Id: I6ea1c13282fbcd70253b9b2939aed37580dbd160 Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
@@ -213,6 +213,9 @@ HEADERS += \
|
||||
$$PWD/includesearchpath.h \
|
||||
$$PWD/commandlinebuilder.h \
|
||||
$$PWD/projectpartartefact.h \
|
||||
$$PWD/projectpartcontainer.h
|
||||
$$PWD/projectpartcontainer.h \
|
||||
$$PWD/sourceentry.h \
|
||||
$$PWD/modifiedtimecheckerinterface.h \
|
||||
$$PWD/modifiedtimechecker.h
|
||||
|
||||
contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
|
||||
|
||||
@@ -25,17 +25,18 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "filepathcachinginterface.h"
|
||||
#include "modifiedtimecheckerinterface.h"
|
||||
|
||||
#include <filepathcachinginterface.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class ModifiedTimeChecker final : public ModifiedTimeCheckerInterface
|
||||
template<typename SourceEntries = ::ClangBackEnd::SourceEntries>
|
||||
class ModifiedTimeChecker final : public ModifiedTimeCheckerInterface<SourceEntries>
|
||||
{
|
||||
using SourceEntry = typename SourceEntries::value_type;
|
||||
|
||||
public:
|
||||
using GetModifiedTime = std::function<ClangBackEnd::TimeStamp(ClangBackEnd::FilePathView filePath)>;
|
||||
ModifiedTimeChecker(GetModifiedTime &getModifiedTime, FilePathCachingInterface &filePathCache)
|
||||
@@ -67,7 +68,7 @@ public:
|
||||
std::back_inserter(timeStampsToUpdate));
|
||||
|
||||
for (SourceTimeStamp &sourceTimeStamp : timeStampsToUpdate) {
|
||||
sourceTimeStamp.lastModified = m_getModifiedTime(
|
||||
sourceTimeStamp.timeStamp = m_getModifiedTime(
|
||||
m_filePathCache.filePath(sourceTimeStamp.sourceId));
|
||||
}
|
||||
}
|
||||
@@ -78,21 +79,22 @@ private:
|
||||
class CompareSourceId
|
||||
{
|
||||
public:
|
||||
bool operator()(SourceTimeStamp first, SourceTimeStamp second) {
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(SourceEntry first, SourceEntry second)
|
||||
bool operator()(SourceTimeStamp first, SourceTimeStamp second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(SourceTimeStamp first, SourceEntry second)
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(SourceEntry first, SourceTimeStamp second)
|
||||
bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
@@ -112,23 +114,22 @@ private:
|
||||
public:
|
||||
bool operator()(SourceTimeStamp first, SourceTimeStamp second)
|
||||
{
|
||||
return first.lastModified <= second.lastModified;
|
||||
return first.timeStamp <= second.timeStamp;
|
||||
}
|
||||
|
||||
bool operator()(SourceEntry first, SourceEntry second)
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.pchCreationTimeStamp <=
|
||||
second.pchCreationTimeStamp;
|
||||
return first.timeStamp <= second.timeStamp;
|
||||
}
|
||||
|
||||
bool operator()(SourceTimeStamp first, SourceEntry second)
|
||||
bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.lastModified <= second.pchCreationTimeStamp;
|
||||
return first.timeStamp <= second.timeStamp;
|
||||
}
|
||||
|
||||
bool operator()(SourceEntry first, SourceTimeStamp second)
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
|
||||
{
|
||||
return first.pchCreationTimeStamp <= second.lastModified;
|
||||
return first.timeStamp <= second.timeStamp;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -144,7 +145,7 @@ private:
|
||||
SourceTimeStamps sourceTimeStamps = newSourceTimeStamps(sourceEntries);
|
||||
|
||||
for (SourceTimeStamp &newSourceTimeStamp : sourceTimeStamps) {
|
||||
newSourceTimeStamp.lastModified = m_getModifiedTime(
|
||||
newSourceTimeStamp.timeStamp = m_getModifiedTime(
|
||||
m_filePathCache.filePath(newSourceTimeStamp.sourceId));
|
||||
}
|
||||
|
||||
@@ -169,17 +170,17 @@ private:
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(SourceEntry first, SourceEntry second)
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(SourceTimeStamp first, SourceEntry second)
|
||||
bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(SourceEntry first, SourceTimeStamp second)
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
template<typename SourceEntries = ::ClangBackEnd::SourceEntries>
|
||||
class ModifiedTimeCheckerInterface
|
||||
{
|
||||
public:
|
||||
@@ -245,6 +245,22 @@ public:
|
||||
return statement.template value<ProjectPartArtefact, 8>(projectPartId.projectPathId);
|
||||
}
|
||||
|
||||
void resetIndexingTimeStamps(const ProjectPartContainers &projectsParts) override
|
||||
{
|
||||
try {
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
||||
for (const ProjectPartContainer &projectPart : projectsParts) {
|
||||
for (FilePathId sourcePathId : projectPart.sourcePathIds)
|
||||
resetDependentIndexingTimeStampsStatement.write(sourcePathId.filePathId);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
} catch (const Sqlite::StatementIsBusy &) {
|
||||
resetIndexingTimeStamps(projectsParts);
|
||||
}
|
||||
}
|
||||
|
||||
Sqlite::TransactionInterface &transactionBackend() override { return database; }
|
||||
|
||||
static Utils::SmallString toJson(const Utils::SmallStringVector &strings)
|
||||
@@ -343,5 +359,11 @@ public:
|
||||
"SELECT sourceId FROM projectPartsSources WHERE projectPartId = ?", database};
|
||||
mutable ReadStatement fetchProjectPrecompiledHeaderPathStatement{
|
||||
"SELECT projectPchPath FROM precompiledHeaders WHERE projectPartId = ?", database};
|
||||
WriteStatement resetDependentIndexingTimeStampsStatement{
|
||||
"WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION SELECT "
|
||||
"dependencySourceId FROM sourceDependencies, collectedDependencies WHERE "
|
||||
"sourceDependencies.sourceId == collectedDependencies.sourceId) UPDATE fileStatuses SET "
|
||||
"indexingTimeStamp = NULL WHERE sourceId IN (SELECT sourceId FROM collectedDependencies)",
|
||||
database};
|
||||
};
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(FilePathId sourceId) const = 0;
|
||||
virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(
|
||||
ProjectPartId projectPartId) const = 0;
|
||||
virtual void resetIndexingTimeStamps(const ProjectPartContainers &projectsParts) = 0;
|
||||
|
||||
virtual Sqlite::TransactionInterface &transactionBackend() = 0;
|
||||
|
||||
|
||||
@@ -177,6 +177,7 @@ public:
|
||||
Sqlite::Contraint::PrimaryKey);
|
||||
table.addColumn("size", Sqlite::ColumnType::Integer);
|
||||
table.addColumn("lastModified", Sqlite::ColumnType::Integer);
|
||||
table.addColumn("indexingTimeStamp", Sqlite::ColumnType::Integer);
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
@@ -188,6 +189,7 @@ public:
|
||||
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
|
||||
const Sqlite::Column &dependencySourceIdColumn = table.addColumn("dependencySourceId", Sqlite::ColumnType::Integer);
|
||||
table.addIndex({sourceIdColumn, dependencySourceIdColumn});
|
||||
table.addIndex({dependencySourceIdColumn, sourceIdColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
@@ -64,12 +64,12 @@ class SourceTimeStamp
|
||||
using int64 = long long;
|
||||
public:
|
||||
SourceTimeStamp(int sourceId, int64 lastModified)
|
||||
: lastModified(lastModified)
|
||||
: timeStamp(lastModified)
|
||||
, sourceId(sourceId)
|
||||
{}
|
||||
|
||||
SourceTimeStamp(FilePathId sourceId, TimeStamp lastModified)
|
||||
: lastModified(lastModified)
|
||||
: timeStamp(lastModified)
|
||||
, sourceId(sourceId)
|
||||
{}
|
||||
|
||||
@@ -90,7 +90,7 @@ public:
|
||||
|
||||
friend bool operator==(SourceTimeStamp first, SourceTimeStamp second)
|
||||
{
|
||||
return first.sourceId == second.sourceId && first.lastModified == second.lastModified;
|
||||
return first.sourceId == second.sourceId && first.timeStamp == second.timeStamp;
|
||||
}
|
||||
|
||||
friend bool operator!=(SourceTimeStamp first, SourceTimeStamp second)
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
TimeStamp lastModified;
|
||||
TimeStamp timeStamp;
|
||||
FilePathId sourceId;
|
||||
};
|
||||
|
||||
@@ -110,21 +110,22 @@ class SourceEntry
|
||||
using int64 = long long;
|
||||
|
||||
public:
|
||||
SourceEntry(int sourceId,
|
||||
int64 pchCreationTimeStamp,
|
||||
int sourceType,
|
||||
int hasMissingIncludes)
|
||||
: pchCreationTimeStamp(pchCreationTimeStamp), sourceId(sourceId),
|
||||
sourceType(static_cast<SourceType>(sourceType)),
|
||||
hasMissingIncludes(
|
||||
static_cast<HasMissingIncludes>(hasMissingIncludes)) {}
|
||||
SourceEntry(int sourceId, int64 timeStamp, int sourceType, int hasMissingIncludes)
|
||||
: timeStamp(timeStamp)
|
||||
, sourceId(sourceId)
|
||||
, sourceType(static_cast<SourceType>(sourceType))
|
||||
, hasMissingIncludes(static_cast<HasMissingIncludes>(hasMissingIncludes))
|
||||
{}
|
||||
|
||||
SourceEntry(FilePathId sourceId,
|
||||
SourceType sourceType,
|
||||
TimeStamp pchCreationTimeStamp,
|
||||
TimeStamp timeStamp,
|
||||
HasMissingIncludes hasMissingIncludes = HasMissingIncludes::No)
|
||||
: pchCreationTimeStamp(pchCreationTimeStamp), sourceId(sourceId),
|
||||
sourceType(sourceType), hasMissingIncludes(hasMissingIncludes) {}
|
||||
: timeStamp(timeStamp)
|
||||
, sourceId(sourceId)
|
||||
, sourceType(sourceType)
|
||||
, hasMissingIncludes(hasMissingIncludes)
|
||||
{}
|
||||
|
||||
friend bool operator<(SourceEntry first, SourceEntry second) {
|
||||
return first.sourceId < second.sourceId;
|
||||
@@ -133,13 +134,13 @@ public:
|
||||
friend bool operator==(SourceEntry first, SourceEntry second)
|
||||
{
|
||||
return first.sourceId == second.sourceId && first.sourceType == second.sourceType
|
||||
&& first.pchCreationTimeStamp == second.pchCreationTimeStamp;
|
||||
&& first.timeStamp == second.timeStamp;
|
||||
}
|
||||
|
||||
friend bool operator!=(SourceEntry first, SourceEntry second) { return !(first == second); }
|
||||
|
||||
public:
|
||||
TimeStamp pchCreationTimeStamp;
|
||||
TimeStamp timeStamp;
|
||||
FilePathId sourceId;
|
||||
SourceType sourceType = SourceType::UserInclude;
|
||||
HasMissingIncludes hasMissingIncludes = HasMissingIncludes::No;
|
||||
@@ -47,7 +47,7 @@ void CompletionChunksToTextConverter::parseChunks(
|
||||
m_codeCompletionChunks.cend(),
|
||||
[this] (const ClangBackEnd::CodeCompletionChunk &chunk)
|
||||
{
|
||||
parseDependendOnTheOptionalState(chunk);
|
||||
parseDependentOnTheOptionalState(chunk);
|
||||
m_previousCodeCompletionChunk = chunk;
|
||||
});
|
||||
}
|
||||
@@ -200,7 +200,7 @@ void CompletionChunksToTextConverter::parse(
|
||||
}
|
||||
}
|
||||
|
||||
void CompletionChunksToTextConverter::parseDependendOnTheOptionalState(
|
||||
void CompletionChunksToTextConverter::parseDependentOnTheOptionalState(
|
||||
const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk)
|
||||
{
|
||||
wrapInCursiveTagIfOptional(codeCompletionChunk);
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
|
||||
private:
|
||||
void parse(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk);
|
||||
void parseDependendOnTheOptionalState(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk);
|
||||
void parseDependentOnTheOptionalState(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk);
|
||||
void parseResultType(const Utf8String &text);
|
||||
void parseText(const Utf8String &text);
|
||||
void wrapInCursiveTagIfOptional(const ClangBackEnd::CodeCompletionChunk &codeCompletionChunk);
|
||||
|
||||
@@ -455,6 +455,8 @@ void CompilerOptionsBuilder::addLanguageVersionAndExtensions()
|
||||
case LanguageVersion::CXX2a:
|
||||
option = (gnuExtensions ? QLatin1String("-std=gnu++2a") : QLatin1String("-std=c++2a"));
|
||||
break;
|
||||
case LanguageVersion::None:
|
||||
break;
|
||||
}
|
||||
|
||||
add(option, /*gccOnlyOption=*/true);
|
||||
|
||||
@@ -215,7 +215,8 @@ struct Data // because we have a cycle dependency
|
||||
[&](ClangBackEnd::FilePathView path) -> TimeStamp {
|
||||
return QFileInfo(QString(path)).lastModified().toSecsSinceEpoch();
|
||||
}};
|
||||
ClangBackEnd::ModifiedTimeChecker modifiedTimeChecker{getModifiedTime, filePathCache};
|
||||
ClangBackEnd::ModifiedTimeChecker<ClangBackEnd::SourceEntries> modifiedTimeChecker{getModifiedTime,
|
||||
filePathCache};
|
||||
ClangBackEnd::BuildDependenciesProvider buildDependencyProvider{buildDependencyStorage,
|
||||
modifiedTimeChecker,
|
||||
buildDependencyCollector,
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
|
||||
#include "builddependenciesproviderinterface.h"
|
||||
|
||||
#include <modifiedtimecheckerinterface.h>
|
||||
|
||||
namespace Sqlite {
|
||||
class TransactionInterface;
|
||||
}
|
||||
@@ -34,14 +36,13 @@ class TransactionInterface;
|
||||
namespace ClangBackEnd {
|
||||
|
||||
class BuildDependenciesStorageInterface;
|
||||
class ModifiedTimeCheckerInterface;
|
||||
class BuildDependencyGeneratorInterface;
|
||||
|
||||
class BuildDependenciesProvider : public BuildDependenciesProviderInterface
|
||||
{
|
||||
public:
|
||||
BuildDependenciesProvider(BuildDependenciesStorageInterface &buildDependenciesStorage,
|
||||
ModifiedTimeCheckerInterface &modifiedTimeChecker,
|
||||
ModifiedTimeCheckerInterface<> &modifiedTimeChecker,
|
||||
BuildDependencyGeneratorInterface &buildDependenciesGenerator,
|
||||
Sqlite::TransactionInterface &transactionBackend)
|
||||
: m_storage(buildDependenciesStorage)
|
||||
@@ -61,7 +62,7 @@ private:
|
||||
|
||||
private:
|
||||
BuildDependenciesStorageInterface &m_storage;
|
||||
ModifiedTimeCheckerInterface &m_modifiedTimeChecker;
|
||||
ModifiedTimeCheckerInterface<> &m_modifiedTimeChecker;
|
||||
BuildDependencyGeneratorInterface &m_generator;
|
||||
Sqlite::TransactionInterface &m_transactionBackend;
|
||||
};
|
||||
|
||||
@@ -29,8 +29,6 @@ HEADERS += \
|
||||
$$PWD/builddependenciesprovider.h \
|
||||
$$PWD/builddependenciesstorageinterface.h \
|
||||
$$PWD/builddependency.h \
|
||||
$$PWD/modifiedtimecheckerinterface.h \
|
||||
$$PWD/sourceentry.h \
|
||||
$$PWD/builddependenciesstorage.h \
|
||||
$$PWD/builddependencygeneratorinterface.h \
|
||||
$$PWD/usedmacrofilter.h \
|
||||
@@ -40,8 +38,7 @@ HEADERS += \
|
||||
$$PWD/pchtaskqueue.h \
|
||||
$$PWD/generatepchactionfactory.h \
|
||||
$$PWD/pchtaskgeneratorinterface.h \
|
||||
$$PWD/toolchainargumentscache.h \
|
||||
$$PWD/modifiedtimechecker.h
|
||||
$$PWD/toolchainargumentscache.h
|
||||
|
||||
!isEmpty(LIBTOOLING_LIBS) {
|
||||
SOURCES += \
|
||||
|
||||
@@ -293,7 +293,7 @@ public:
|
||||
entry.get().hasMissingIncludes = HasMissingIncludes::Yes;
|
||||
}
|
||||
|
||||
SourceDependencies sourceDependenciesSortedByDependendFilePathId() const
|
||||
SourceDependencies sourceDependenciesSortedByDependentFilePathId() const
|
||||
{
|
||||
auto sourceDependencies = m_buildDependency.sourceDependencies;
|
||||
std::sort(sourceDependencies.begin(), sourceDependencies.end(), [](auto first, auto second) {
|
||||
@@ -309,7 +309,7 @@ public:
|
||||
sortAndMakeUnique(m_containsMissingIncludes);
|
||||
|
||||
collectSourceWithMissingIncludes(m_containsMissingIncludes,
|
||||
sourceDependenciesSortedByDependendFilePathId());
|
||||
sourceDependenciesSortedByDependentFilePathId());
|
||||
|
||||
removeSourceWithMissingIncludesFromSources();
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ ProjectPartContainers ProjectPartsManager::update(ProjectPartContainers &&projec
|
||||
}
|
||||
|
||||
m_projectPartsStorage.updateProjectParts(updatedProjectParts);
|
||||
|
||||
m_projectPartsStorage.resetIndexingTimeStamps(updatedProjectParts);
|
||||
m_precompiledHeaderStorage.deleteProjectPrecompiledHeaders(
|
||||
toProjectPartIds(updatedProjectParts));
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ SymbolIndexer::SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQ
|
||||
FilePathCachingInterface &filePathCache,
|
||||
FileStatusCache &fileStatusCache,
|
||||
Sqlite::TransactionInterface &transactionInterface,
|
||||
ProjectPartsStorageInterface &projectPartsStorage)
|
||||
ProjectPartsStorageInterface &projectPartsStorage,
|
||||
ModifiedTimeCheckerInterface<SourceTimeStamps> &modifiedTimeChecker)
|
||||
: m_symbolIndexerTaskQueue(symbolIndexerTaskQueue)
|
||||
, m_symbolStorage(symbolStorage)
|
||||
, m_buildDependencyStorage(buildDependenciesStorage)
|
||||
@@ -76,6 +77,7 @@ SymbolIndexer::SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQ
|
||||
, m_fileStatusCache(fileStatusCache)
|
||||
, m_transactionInterface(transactionInterface)
|
||||
, m_projectPartsStorage(projectPartsStorage)
|
||||
, m_modifiedTimeChecker(modifiedTimeChecker)
|
||||
{
|
||||
pathWatcher.setNotifier(this);
|
||||
}
|
||||
@@ -109,16 +111,19 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart)
|
||||
std::vector<SymbolIndexerTask> symbolIndexerTask;
|
||||
symbolIndexerTask.reserve(projectPart.sourcePathIds.size());
|
||||
for (FilePathId sourcePathId : projectPart.sourcePathIds) {
|
||||
auto indexing = [arguments = commandLineBuilder.commandLine,
|
||||
sourcePathId,
|
||||
this](SymbolsCollectorInterface &symbolsCollector) {
|
||||
SourceTimeStamps dependentTimeStamps = m_symbolStorage.fetchIncludedIndexingTimeStamps(
|
||||
sourcePathId);
|
||||
|
||||
if (!m_modifiedTimeChecker.isUpToDate(dependentTimeStamps)) {
|
||||
auto indexing = [arguments = commandLineBuilder.commandLine, sourcePathId, this](
|
||||
SymbolsCollectorInterface &symbolsCollector) {
|
||||
symbolsCollector.setFile(sourcePathId, arguments);
|
||||
|
||||
bool success = symbolsCollector.collectSymbols();
|
||||
|
||||
if (success) {
|
||||
Sqlite::ImmediateTransaction transaction{m_transactionInterface};
|
||||
|
||||
m_symbolStorage.insertOrUpdateIndexingTimeStamps(symbolsCollector.fileStatuses());
|
||||
m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(),
|
||||
symbolsCollector.sourceLocations());
|
||||
transaction.commit();
|
||||
@@ -127,6 +132,7 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart)
|
||||
|
||||
symbolIndexerTask.emplace_back(sourcePathId, projectPartId, std::move(indexing));
|
||||
}
|
||||
}
|
||||
|
||||
m_symbolIndexerTaskQueue.addOrUpdateTasks(std::move(symbolIndexerTask));
|
||||
m_symbolIndexerTaskQueue.processEntries();
|
||||
@@ -136,11 +142,13 @@ void SymbolIndexer::pathsWithIdsChanged(const ProjectPartIds &) {}
|
||||
|
||||
void SymbolIndexer::pathsChanged(const FilePathIds &filePathIds)
|
||||
{
|
||||
std::vector<SymbolIndexerTask> symbolIndexerTask;
|
||||
symbolIndexerTask.reserve(filePathIds.size());
|
||||
FilePathIds dependentSourcePathIds = m_symbolStorage.fetchDependentSourceIds(filePathIds);
|
||||
|
||||
for (FilePathId filePathId : filePathIds)
|
||||
updateChangedPath(filePathId, symbolIndexerTask);
|
||||
std::vector<SymbolIndexerTask> symbolIndexerTask;
|
||||
symbolIndexerTask.reserve(dependentSourcePathIds.size());
|
||||
|
||||
for (FilePathId dependentSourcePathId : dependentSourcePathIds)
|
||||
updateChangedPath(dependentSourcePathId, symbolIndexerTask);
|
||||
|
||||
m_symbolIndexerTaskQueue.addOrUpdateTasks(std::move(symbolIndexerTask));
|
||||
m_symbolIndexerTaskQueue.processEntries();
|
||||
@@ -161,6 +169,8 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId,
|
||||
= m_precompiledHeaderStorage.fetchPrecompiledHeader(optionalArtefact->projectPartId);
|
||||
transaction.commit();
|
||||
|
||||
SourceTimeStamps dependentTimeStamps = m_symbolStorage.fetchIncludedIndexingTimeStamps(filePathId);
|
||||
|
||||
const ProjectPartArtefact &artefact = *optionalArtefact;
|
||||
|
||||
auto pchPath = optionalProjectPartPch ? optionalProjectPartPch->pchPath : FilePath{};
|
||||
@@ -176,10 +186,9 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId,
|
||||
|
||||
if (success) {
|
||||
Sqlite::ImmediateTransaction transaction{m_transactionInterface};
|
||||
|
||||
m_symbolStorage.insertOrUpdateIndexingTimeStamps(symbolsCollector.fileStatuses());
|
||||
m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(),
|
||||
symbolsCollector.sourceLocations());
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include "clangpathwatcher.h"
|
||||
|
||||
#include <filecontainerv2.h>
|
||||
#include <modifiedtimecheckerinterface.h>
|
||||
#include <precompiledheaderstorageinterface.h>
|
||||
#include <projectpartcontainer.h>
|
||||
#include <projectpartsstorageinterface.h>
|
||||
@@ -51,7 +52,8 @@ public:
|
||||
FilePathCachingInterface &filePathCache,
|
||||
FileStatusCache &fileStatusCache,
|
||||
Sqlite::TransactionInterface &transactionInterface,
|
||||
ProjectPartsStorageInterface &projectPartsStorage);
|
||||
ProjectPartsStorageInterface &projectPartsStorage,
|
||||
ModifiedTimeCheckerInterface<SourceTimeStamps> &modifiedTimeChecker);
|
||||
|
||||
void updateProjectParts(ProjectPartContainers &&projectParts);
|
||||
void updateProjectPart(ProjectPartContainer &&projectPart);
|
||||
@@ -81,6 +83,7 @@ private:
|
||||
FileStatusCache &m_fileStatusCache;
|
||||
Sqlite::TransactionInterface &m_transactionInterface;
|
||||
ProjectPartsStorageInterface &m_projectPartsStorage;
|
||||
ModifiedTimeCheckerInterface<SourceTimeStamps> &m_modifiedTimeChecker;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -38,13 +38,16 @@
|
||||
#include <precompiledheaderstorage.h>
|
||||
#include <projectpartsstorage.h>
|
||||
|
||||
#include <refactoringdatabaseinitializer.h>
|
||||
#include <filepathcachingfwd.h>
|
||||
#include <modifiedtimechecker.h>
|
||||
#include <refactoringdatabaseinitializer.h>
|
||||
|
||||
#include <sqlitedatabase.h>
|
||||
#include <sqlitereadstatement.h>
|
||||
#include <sqlitewritestatement.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QFileInfo>
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
#include <thread>
|
||||
@@ -130,6 +133,12 @@ private:
|
||||
FileStatusCache m_fileStatusCache{m_filePathCache};
|
||||
SymbolsCollectorManager m_collectorManger;
|
||||
ProgressCounter m_progressCounter;
|
||||
std::function<TimeStamp(FilePathView filePath)> getModifiedTime{
|
||||
[&](ClangBackEnd::FilePathView path) -> TimeStamp {
|
||||
return QFileInfo(QString(path)).lastModified().toSecsSinceEpoch();
|
||||
}};
|
||||
ModifiedTimeChecker<ClangBackEnd::SourceTimeStamps> m_modifiedTimeChecker{getModifiedTime,
|
||||
m_filePathCache};
|
||||
SymbolIndexer m_indexer{m_indexerQueue,
|
||||
m_symbolStorage,
|
||||
m_buildDependencyStorage,
|
||||
@@ -138,7 +147,8 @@ private:
|
||||
m_filePathCache,
|
||||
m_fileStatusCache,
|
||||
m_symbolStorage.database,
|
||||
m_projectPartsStorage};
|
||||
m_projectPartsStorage,
|
||||
m_modifiedTimeChecker};
|
||||
SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler, m_progressCounter};
|
||||
SymbolIndexerTaskScheduler m_indexerScheduler;
|
||||
};
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
template <typename DatabaseType>
|
||||
template<typename DatabaseType = Sqlite::Database>
|
||||
class SymbolStorage final : public SymbolStorageInterface
|
||||
{
|
||||
using Database = DatabaseType;
|
||||
@@ -70,6 +70,93 @@ public:
|
||||
deleteNewLocationsTable();
|
||||
}
|
||||
|
||||
void insertOrUpdateIndexingTimeStamps(const FilePathIds &filePathIds, TimeStamp indexingTimeStamp)
|
||||
{
|
||||
try {
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
||||
for (FilePathId filePathId : filePathIds) {
|
||||
inserOrUpdateIndexingTimesStampStatement.write(filePathId.filePathId,
|
||||
indexingTimeStamp.value);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
} catch (const Sqlite::StatementIsBusy &) {
|
||||
insertOrUpdateIndexingTimeStamps(filePathIds, indexingTimeStamp);
|
||||
}
|
||||
}
|
||||
|
||||
void insertOrUpdateIndexingTimeStamps(const FileStatuses &fileStatuses) override
|
||||
{
|
||||
for (FileStatus fileStatus : fileStatuses) {
|
||||
inserOrUpdateIndexingTimesStampStatement.write(fileStatus.filePathId.filePathId,
|
||||
fileStatus.lastModified);
|
||||
}
|
||||
}
|
||||
|
||||
SourceTimeStamps fetchIndexingTimeStamps() const
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto timeStamps = fetchIndexingTimeStampsStatement.template values<SourceTimeStamp, 2>(
|
||||
1024);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return timeStamps;
|
||||
} catch (const Sqlite::StatementIsBusy &) {
|
||||
return fetchIndexingTimeStamps();
|
||||
}
|
||||
}
|
||||
|
||||
SourceTimeStamps fetchIncludedIndexingTimeStamps(FilePathId sourcePathId) const
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto timeStamps = fetchIncludedIndexingTimeStampsStatement
|
||||
.template values<SourceTimeStamp, 2>(1024, sourcePathId.filePathId);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return timeStamps;
|
||||
} catch (const Sqlite::StatementIsBusy &) {
|
||||
return fetchIncludedIndexingTimeStamps(sourcePathId);
|
||||
}
|
||||
}
|
||||
|
||||
FilePathIds fetchDependentSourceIds(const FilePathIds &sourcePathIds) const override
|
||||
{
|
||||
try {
|
||||
FilePathIds dependentSourceIds;
|
||||
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
for (FilePathId sourcePathId : sourcePathIds) {
|
||||
FilePathIds newDependentSourceIds;
|
||||
newDependentSourceIds.reserve(dependentSourceIds.size() + 1024);
|
||||
|
||||
auto newIds = fetchDependentSourceIdsStatement
|
||||
.template values<FilePathId>(1024, sourcePathId.filePathId);
|
||||
|
||||
std::set_union(dependentSourceIds.begin(),
|
||||
dependentSourceIds.end(),
|
||||
newIds.begin(),
|
||||
newIds.end(),
|
||||
std::back_inserter(newDependentSourceIds));
|
||||
|
||||
dependentSourceIds = std::move(newDependentSourceIds);
|
||||
}
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return dependentSourceIds;
|
||||
} catch (const Sqlite::StatementIsBusy &) {
|
||||
return fetchDependentSourceIds(sourcePathIds);
|
||||
}
|
||||
}
|
||||
|
||||
void fillTemporarySymbolsTable(const SymbolEntries &symbolEntries)
|
||||
{
|
||||
WriteStatement &statement = insertSymbolsToNewSymbolsStatement;
|
||||
@@ -191,6 +278,25 @@ public:
|
||||
database};
|
||||
WriteStatement deleteNewSymbolsTableStatement{"DELETE FROM newSymbols", database};
|
||||
WriteStatement deleteNewLocationsTableStatement{"DELETE FROM newLocations", database};
|
||||
WriteStatement inserOrUpdateIndexingTimesStampStatement{
|
||||
"INSERT INTO fileStatuses(sourceId, indexingTimeStamp) VALUES (?001, ?002) ON "
|
||||
"CONFLICT(sourceId) DO UPDATE SET indexingTimeStamp = ?002",
|
||||
database};
|
||||
mutable ReadStatement fetchIncludedIndexingTimeStampsStatement{
|
||||
"WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION SELECT "
|
||||
"dependencySourceId FROM sourceDependencies, collectedDependencies WHERE "
|
||||
"sourceDependencies.sourceId == collectedDependencies.sourceId) SELECT DISTINCT sourceId, "
|
||||
"indexingTimeStamp FROM collectedDependencies NATURAL JOIN fileStatuses ORDER BY sourceId",
|
||||
database};
|
||||
mutable ReadStatement fetchIndexingTimeStampsStatement{
|
||||
"SELECT sourceId, indexingTimeStamp FROM fileStatuses", database};
|
||||
mutable ReadStatement fetchDependentSourceIdsStatement{
|
||||
"WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION SELECT "
|
||||
"sourceDependencies.sourceId FROM sourceDependencies, collectedDependencies WHERE "
|
||||
"sourceDependencies.dependencySourceId == collectedDependencies.sourceId) SELECT sourceId "
|
||||
"FROM collectedDependencies WHERE sourceId NOT IN (SELECT dependencySourceId FROM "
|
||||
"sourceDependencies) ORDER BY sourceId",
|
||||
database};
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
#include "sourcelocationentry.h"
|
||||
#include "symbolentry.h"
|
||||
|
||||
#include <filestatus.h>
|
||||
#include <sourceentry.h>
|
||||
|
||||
#include <compilermacro.h>
|
||||
#include <sqlitetransaction.h>
|
||||
|
||||
@@ -45,6 +48,11 @@ public:
|
||||
virtual void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries,
|
||||
const SourceLocationEntries &sourceLocations)
|
||||
= 0;
|
||||
virtual void insertOrUpdateIndexingTimeStamps(const FilePathIds &filePathIds, TimeStamp indexingTimeStamp) = 0;
|
||||
virtual void insertOrUpdateIndexingTimeStamps(const FileStatuses &fileStatuses) = 0;
|
||||
virtual SourceTimeStamps fetchIndexingTimeStamps() const = 0;
|
||||
virtual SourceTimeStamps fetchIncludedIndexingTimeStamps(FilePathId sourcePathId) const = 0;
|
||||
virtual FilePathIds fetchDependentSourceIds(const FilePathIds &sourcePathIds) const = 0;
|
||||
|
||||
protected:
|
||||
~SymbolStorageInterface() = default;
|
||||
|
||||
@@ -58,7 +58,7 @@ class BuildDependenciesProvider : public testing::Test
|
||||
protected:
|
||||
NiceMock<MockSqliteTransactionBackend> mockSqliteTransactionBackend;
|
||||
NiceMock<MockBuildDependenciesStorage> mockBuildDependenciesStorage;
|
||||
NiceMock<MockModifiedTimeChecker> mockModifiedTimeChecker;
|
||||
NiceMock<MockSourceEntriesModifiedTimeChecker> mockModifiedTimeChecker;
|
||||
NiceMock<MockBuildDependencyGenerator> mockBuildDependenciesGenerator;
|
||||
ClangBackEnd::BuildDependenciesProvider provider{mockBuildDependenciesStorage,
|
||||
mockModifiedTimeChecker,
|
||||
|
||||
@@ -201,7 +201,7 @@ TEST_F(DocumentSlowTest, NeedsReparseAfterChangeOfMainFile)
|
||||
ASSERT_TRUE(document.isDirty());
|
||||
}
|
||||
|
||||
TEST_F(DocumentSlowTest, NoNeedForReparsingForIndependendFile)
|
||||
TEST_F(DocumentSlowTest, NoNeedForReparsingForIndependentFile)
|
||||
{
|
||||
document.parse();
|
||||
|
||||
@@ -210,7 +210,7 @@ TEST_F(DocumentSlowTest, NoNeedForReparsingForIndependendFile)
|
||||
ASSERT_FALSE(document.isDirty());
|
||||
}
|
||||
|
||||
TEST_F(DocumentSlowTest, NeedsReparsingForDependendFile)
|
||||
TEST_F(DocumentSlowTest, NeedsReparsingForDependentFile)
|
||||
{
|
||||
document.parse();
|
||||
|
||||
|
||||
@@ -97,16 +97,16 @@ TEST_F(UpdateAnnotationsJobSlowTest, DontSendAnnotationsIfDocumentRevisionChange
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
}
|
||||
|
||||
TEST_F(UpdateAnnotationsJobSlowTest, UpdatesDependendFilePaths)
|
||||
TEST_F(UpdateAnnotationsJobSlowTest, UpdatesDependentFilePaths)
|
||||
{
|
||||
const QSet<Utf8String> dependendOnFilesBefore = document.dependedFilePaths();
|
||||
const QSet<Utf8String> dependentOnFilesBefore = document.dependedFilePaths();
|
||||
job.setContext(jobContext);
|
||||
job.prepareAsyncRun();
|
||||
|
||||
job.runAsync();
|
||||
ASSERT_TRUE(waitUntilJobFinished(job));
|
||||
|
||||
ASSERT_THAT(dependendOnFilesBefore, Not(document.dependedFilePaths()));
|
||||
ASSERT_THAT(dependentOnFilesBefore, Not(document.dependedFilePaths()));
|
||||
}
|
||||
|
||||
TEST_F(UpdateAnnotationsJobSlowTest, UpdatesUnresolvedFilePaths)
|
||||
|
||||
@@ -1230,6 +1230,16 @@ std::ostream &operator<<(std::ostream &out, const SourceEntry &entry)
|
||||
<< typeToString(entry.hasMissingIncludes) << ")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const SourceTimeStamp &sourceTimeStamp)
|
||||
{
|
||||
return out << "(" << sourceTimeStamp.sourceId << ", " << sourceTimeStamp.timeStamp << ")";
|
||||
}
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const TimeStamp &timeStamp)
|
||||
{
|
||||
return out << timeStamp.value;
|
||||
}
|
||||
|
||||
const char *typeToString(IncludeSearchPathType type)
|
||||
{
|
||||
switch (type) {
|
||||
|
||||
@@ -190,6 +190,8 @@ class PchTask;
|
||||
class PchTaskSet;
|
||||
class BuildDependency;
|
||||
class SourceEntry;
|
||||
class SourceTimeStamp;
|
||||
class TimeStamp;
|
||||
class FilePathCaching;
|
||||
struct SlotUsage;
|
||||
class IncludeSearchPath;
|
||||
@@ -281,6 +283,8 @@ std::ostream &operator<<(std::ostream &out, const PchTask &task);
|
||||
std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet);
|
||||
std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency);
|
||||
std::ostream &operator<<(std::ostream &out, const SourceEntry &entry);
|
||||
std::ostream &operator<<(std::ostream &out, const SourceTimeStamp &sourceTimeStamp);
|
||||
std::ostream &operator<<(std::ostream &out, const TimeStamp &timeStamp);
|
||||
std::ostream &operator<<(std::ostream &out, const SlotUsage &slotUsage);
|
||||
std::ostream &operator<<(std::ostream &out, const IncludeSearchPathType &pathType);
|
||||
std::ostream &operator<<(std::ostream &out, const IncludeSearchPath &path);
|
||||
|
||||
@@ -29,9 +29,17 @@
|
||||
|
||||
#include <modifiedtimecheckerinterface.h>
|
||||
|
||||
class MockModifiedTimeChecker : public ClangBackEnd::ModifiedTimeCheckerInterface
|
||||
class MockSourceEntriesModifiedTimeChecker
|
||||
: public ClangBackEnd::ModifiedTimeCheckerInterface<ClangBackEnd::SourceEntries>
|
||||
{
|
||||
public:
|
||||
MOCK_CONST_METHOD1(isUpToDate,
|
||||
bool (const ClangBackEnd::SourceEntries &sourceEntries));
|
||||
};
|
||||
|
||||
class MockSourceTimeStampsModifiedTimeChecker
|
||||
: public ClangBackEnd::ModifiedTimeCheckerInterface<ClangBackEnd::SourceTimeStamps>
|
||||
{
|
||||
public:
|
||||
MOCK_CONST_METHOD1(isUpToDate, bool(const ClangBackEnd::SourceTimeStamps &sourceTimeStamps));
|
||||
};
|
||||
|
||||
@@ -56,5 +56,7 @@ public:
|
||||
MOCK_CONST_METHOD1(fetchProjectPartArtefact,
|
||||
Utils::optional<ClangBackEnd::ProjectPartArtefact>(
|
||||
ClangBackEnd::ProjectPartId projectPartId));
|
||||
MOCK_METHOD1(resetIndexingTimeStamps,
|
||||
void(const ClangBackEnd::ProjectPartContainers &projectsParts));
|
||||
MOCK_METHOD0(transactionBackend, Sqlite::TransactionInterface &());
|
||||
};
|
||||
|
||||
@@ -222,6 +222,19 @@ SourceEntries MockSqliteReadStatement::values<SourceEntry, 4>(std::size_t reserv
|
||||
return valuesReturnSourceEntries(reserveSize, filePathId, projectPartId);
|
||||
}
|
||||
|
||||
template<>
|
||||
SourceTimeStamps MockSqliteReadStatement::values<SourceTimeStamp, 2>(std::size_t reserveSize)
|
||||
{
|
||||
return valuesReturnSourceTimeStamps(reserveSize);
|
||||
}
|
||||
|
||||
template<>
|
||||
SourceTimeStamps MockSqliteReadStatement::values<SourceTimeStamp, 2>(std::size_t reserveSize,
|
||||
const int &sourcePathId)
|
||||
{
|
||||
return valuesReturnSourceTimeStamps(reserveSize, sourcePathId);
|
||||
}
|
||||
|
||||
template <>
|
||||
Utils::optional<Sources::SourceNameAndDirectoryId>
|
||||
MockSqliteReadStatement::value<Sources::SourceNameAndDirectoryId, 2>(const int &id)
|
||||
|
||||
@@ -50,6 +50,8 @@
|
||||
using ClangBackEnd::FilePathIds;
|
||||
using ClangBackEnd::SourceEntries;
|
||||
using ClangBackEnd::SourceEntry;
|
||||
using ClangBackEnd::SourceTimeStamp;
|
||||
using ClangBackEnd::SourceTimeStamps;
|
||||
using ClangRefactoring::SourceLocation;
|
||||
using ClangRefactoring::SourceLocations;
|
||||
using std::int64_t;
|
||||
@@ -136,6 +138,9 @@ public:
|
||||
MOCK_METHOD1(valueReturnProjectPartId,
|
||||
Utils::optional<ClangBackEnd::ProjectPartId>(Utils::SmallStringView));
|
||||
|
||||
MOCK_METHOD1(valuesReturnSourceTimeStamps, SourceTimeStamps(std::size_t));
|
||||
MOCK_METHOD2(valuesReturnSourceTimeStamps, SourceTimeStamps(std::size_t, int sourcePathId));
|
||||
|
||||
template <typename ResultType,
|
||||
int ResultTypeCount = 1,
|
||||
typename... QueryType>
|
||||
@@ -283,6 +288,13 @@ SourceEntries MockSqliteReadStatement::values<SourceEntry, 4>(std::size_t reserv
|
||||
const int &,
|
||||
const int &);
|
||||
|
||||
template<>
|
||||
SourceTimeStamps MockSqliteReadStatement::values<SourceTimeStamp, 2>(std::size_t reserveSize);
|
||||
|
||||
template<>
|
||||
SourceTimeStamps MockSqliteReadStatement::values<SourceTimeStamp, 2>(std::size_t reserveSize,
|
||||
const int &sourcePathId);
|
||||
|
||||
template <>
|
||||
Utils::optional<Sources::SourceNameAndDirectoryId>
|
||||
MockSqliteReadStatement::value<Sources::SourceNameAndDirectoryId, 2>(const int&);
|
||||
|
||||
@@ -37,4 +37,11 @@ public:
|
||||
MOCK_METHOD2(addSymbolsAndSourceLocations,
|
||||
void(const ClangBackEnd::SymbolEntries &symbolEentries,
|
||||
const ClangBackEnd::SourceLocationEntries &sourceLocations));
|
||||
MOCK_METHOD2(insertOrUpdateIndexingTimeStamps,
|
||||
void(const FilePathIds &filePathIds, ClangBackEnd::TimeStamp indexingTimeStamp));
|
||||
MOCK_METHOD1(insertOrUpdateIndexingTimeStamps, void(const ClangBackEnd::FileStatuses &));
|
||||
MOCK_CONST_METHOD0(fetchIndexingTimeStamps, ClangBackEnd::SourceTimeStamps());
|
||||
MOCK_CONST_METHOD1(fetchIncludedIndexingTimeStamps,
|
||||
ClangBackEnd::SourceTimeStamps(ClangBackEnd::FilePathId sourcePathId));
|
||||
MOCK_CONST_METHOD1(fetchDependentSourceIds, FilePathIds(const FilePathIds &sourcePathIds));
|
||||
};
|
||||
|
||||
@@ -57,7 +57,7 @@ protected:
|
||||
ClangBackEnd::FilePathCaching filePathCache{database};
|
||||
decltype(getModifiedTimeCallback.AsStdFunction()) callback = getModifiedTimeCallback
|
||||
.AsStdFunction();
|
||||
ClangBackEnd::ModifiedTimeChecker checker{callback, filePathCache};
|
||||
ClangBackEnd::ModifiedTimeChecker<> checker{callback, filePathCache};
|
||||
SourceEntries upToDateEntries = {{id("/path1"), SourceType::UserInclude, 100},
|
||||
{id("/path2"), SourceType::SystemInclude, 30}};
|
||||
SourceEntries notUpToDateEntries = {{id("/path1"), SourceType::UserInclude, 50},
|
||||
|
||||
@@ -302,6 +302,7 @@ TEST_F(ProjectPartsManager, UpdateCallsIfNewProjectPartIsAdded)
|
||||
EXPECT_CALL(mockProjectPartsStorage, updateProjectParts(ElementsAre(projectPartContainer1)));
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage,
|
||||
deleteProjectPrecompiledHeaders(ElementsAre(projectPartContainer1.projectPartId)));
|
||||
EXPECT_CALL(mockProjectPartsStorage, resetIndexingTimeStamps(ElementsAre(projectPartContainer1)));
|
||||
|
||||
manager.update({projectPartContainer1});
|
||||
}
|
||||
@@ -337,6 +338,16 @@ TEST_F(ProjectPartsManager, UpdateCallsNotDeleteProjectPrecompiledHeadersIfNoNew
|
||||
manager.update({projectPartContainer1});
|
||||
}
|
||||
|
||||
TEST_F(ProjectPartsManager, UpdateCallsNotResetIndexingTimeStampsIfNoNewerProjectPartsExists)
|
||||
{
|
||||
manager.update({projectPartContainer1});
|
||||
|
||||
EXPECT_CALL(mockProjectPartsStorage, resetIndexingTimeStamps(ElementsAre(projectPartContainer1)))
|
||||
.Times(0);
|
||||
|
||||
manager.update({projectPartContainer1});
|
||||
}
|
||||
|
||||
TEST_F(ProjectPartsManager, UpdateCallsIfOldProjectPartIsAdded)
|
||||
{
|
||||
EXPECT_CALL(mockProjectPartsStorage,
|
||||
@@ -346,6 +357,8 @@ TEST_F(ProjectPartsManager, UpdateCallsIfOldProjectPartIsAdded)
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage,
|
||||
deleteProjectPrecompiledHeaders(ElementsAre(projectPartContainer1.projectPartId)))
|
||||
.Times(0);
|
||||
EXPECT_CALL(mockProjectPartsStorage, resetIndexingTimeStamps(ElementsAre(projectPartContainer1)))
|
||||
.Times(0);
|
||||
|
||||
manager.update({projectPartContainer1});
|
||||
}
|
||||
@@ -361,6 +374,8 @@ TEST_F(ProjectPartsManager, UpdateCallsIfUpdatedProjectPartIsAdded)
|
||||
updateProjectParts(ElementsAre(updatedProjectPartContainer1)));
|
||||
EXPECT_CALL(mockPrecompiledHeaderStorage,
|
||||
deleteProjectPrecompiledHeaders(ElementsAre(projectPartContainer1.projectPartId)));
|
||||
EXPECT_CALL(mockProjectPartsStorage,
|
||||
resetIndexingTimeStamps(ElementsAre(updatedProjectPartContainer1)));
|
||||
|
||||
manager.update({updatedProjectPartContainer1});
|
||||
}
|
||||
|
||||
@@ -27,12 +27,13 @@
|
||||
|
||||
#include "mocksqlitedatabase.h"
|
||||
|
||||
#include <builddependenciesstorage.h>
|
||||
#include <projectpartsstorage.h>
|
||||
#include <refactoringdatabaseinitializer.h>
|
||||
#include <sqlitedatabase.h>
|
||||
#include <sqlitereadstatement.h>
|
||||
#include <sqlitewritestatement.h>
|
||||
|
||||
#include <symbolstorage.h>
|
||||
namespace {
|
||||
|
||||
using ClangBackEnd::FilePathId;
|
||||
@@ -104,6 +105,7 @@ protected:
|
||||
MockSqliteReadStatement &fetchProjectPartsHeadersByIdStatement = storage.fetchProjectPartsHeadersByIdStatement;
|
||||
MockSqliteReadStatement &fetchProjectPartsSourcesByIdStatement = storage.fetchProjectPartsSourcesByIdStatement;
|
||||
MockSqliteReadStatement &fetchProjectPrecompiledHeaderPathStatement = storage.fetchProjectPrecompiledHeaderPathStatement;
|
||||
MockSqliteWriteStatement &resetDependentIndexingTimeStampsStatement = storage.resetDependentIndexingTimeStampsStatement;
|
||||
IncludeSearchPaths systemIncludeSearchPaths{{"/includes", 1, IncludeSearchPathType::BuiltIn},
|
||||
{"/other/includes", 2, IncludeSearchPathType::System}};
|
||||
IncludeSearchPaths projectIncludeSearchPaths{{"/project/includes", 1, IncludeSearchPathType::User},
|
||||
@@ -424,6 +426,35 @@ TEST_F(ProjectPartsStorage, FetchProjectPartArtefactByProjectPartIdReturnArtefac
|
||||
ASSERT_THAT(result, Eq(artefact));
|
||||
}
|
||||
|
||||
TEST_F(ProjectPartsStorage, ResetDependentIndexingTimeStamps)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockDatabase, immediateBegin());
|
||||
EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(3)));
|
||||
EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(4)));
|
||||
EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(7)));
|
||||
EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(8)));
|
||||
EXPECT_CALL(mockDatabase, commit());
|
||||
|
||||
storage.resetIndexingTimeStamps({projectPart1, projectPart2});
|
||||
}
|
||||
|
||||
TEST_F(ProjectPartsStorage, ResetDependentIndexingTimeStampsIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockDatabase, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""}));
|
||||
EXPECT_CALL(mockDatabase, immediateBegin());
|
||||
EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(3)));
|
||||
EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(4)));
|
||||
EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(7)));
|
||||
EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(8)));
|
||||
EXPECT_CALL(mockDatabase, commit());
|
||||
|
||||
storage.resetIndexingTimeStamps({projectPart1, projectPart2});
|
||||
}
|
||||
|
||||
class ProjectPartsStorageSlow : public testing::Test, public Data
|
||||
{
|
||||
using Storage = ClangBackEnd::ProjectPartsStorage<Sqlite::Database>;
|
||||
@@ -432,6 +463,8 @@ protected:
|
||||
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
||||
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
|
||||
Storage storage{database};
|
||||
ClangBackEnd::SymbolStorage<> symbolStorage{database};
|
||||
ClangBackEnd::BuildDependenciesStorage<> buildDependenciesStorage{database};
|
||||
};
|
||||
|
||||
TEST_F(ProjectPartsStorageSlow, FetchProjectPartName)
|
||||
@@ -469,4 +502,26 @@ TEST_F(ProjectPartsStorageSlow, FetchProjectParts)
|
||||
|
||||
ASSERT_THAT(projectParts, ElementsAre(projectPart1, projectPart2));
|
||||
}
|
||||
|
||||
TEST_F(ProjectPartsStorageSlow, ResetDependentIndexingTimeStamps)
|
||||
{
|
||||
symbolStorage.insertOrUpdateIndexingTimeStamps({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 34);
|
||||
buildDependenciesStorage.insertOrUpdateSourceDependencies(
|
||||
{{3, 1}, {4, 1}, {1, 2}, {7, 5}, {8, 6}, {6, 5}, {9, 10}});
|
||||
|
||||
storage.resetIndexingTimeStamps({projectPart1, projectPart2});
|
||||
|
||||
ASSERT_THAT(symbolStorage.fetchIndexingTimeStamps(),
|
||||
ElementsAre(SourceTimeStamp{1, 0},
|
||||
SourceTimeStamp{2, 0},
|
||||
SourceTimeStamp{3, 0},
|
||||
SourceTimeStamp{4, 0},
|
||||
SourceTimeStamp{5, 0},
|
||||
SourceTimeStamp{6, 0},
|
||||
SourceTimeStamp{7, 0},
|
||||
SourceTimeStamp{8, 0},
|
||||
SourceTimeStamp{9, 34},
|
||||
SourceTimeStamp{10, 34}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -131,7 +131,7 @@ TEST_F(RefactoringDatabaseInitializer, AddFileStatusesTable)
|
||||
mockDatabase,
|
||||
execute(Eq(
|
||||
"CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, "
|
||||
"lastModified INTEGER)")));
|
||||
"lastModified INTEGER, indexingTimeStamp INTEGER)")));
|
||||
|
||||
initializer.createFileStatusesTable();
|
||||
}
|
||||
@@ -140,8 +140,19 @@ TEST_F(RefactoringDatabaseInitializer, AddSourceDependenciesTable)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, "
|
||||
"dependencySourceId INTEGER)")));
|
||||
EXPECT_CALL(
|
||||
mockDatabase,
|
||||
execute(
|
||||
Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON "
|
||||
"sourceDependencies(sourceId, dependencySourceId)")));
|
||||
EXPECT_CALL(
|
||||
mockDatabase,
|
||||
execute(
|
||||
Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_dependencySourceId_sourceId ON "
|
||||
"sourceDependencies(dependencySourceId, sourceId)")));
|
||||
|
||||
initializer.createSourceDependenciesTable();
|
||||
}
|
||||
@@ -189,40 +200,88 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor)
|
||||
|
||||
EXPECT_CALL(mockDatabase, isInitialized()).WillOnce(Return(false));
|
||||
EXPECT_CALL(mockDatabase, exclusiveBegin());
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT, symbolKind INTEGER, signature TEXT)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_symbolKind_symbolName ON symbols(symbolKind, symbolName)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER, locationKind INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_locations_sourceId_line_column ON locations(sourceId, line, column)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON locations(sourceId, locationKind)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, directoryId INTEGER, sourceName TEXT)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_sources_directoryId_sourceName ON sources(directoryId, sourceName)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS directories(directoryId INTEGER PRIMARY KEY, directoryPath TEXT)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_directories_directoryPath ON directories(directoryPath)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr "
|
||||
"TEXT, symbolName TEXT, symbolKind INTEGER, signature TEXT)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_symbolKind_symbolName ON "
|
||||
"symbols(symbolKind, symbolName)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, "
|
||||
"column INTEGER, sourceId INTEGER, locationKind INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_locations_sourceId_line_column "
|
||||
"ON locations(sourceId, line, column)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_locationKind ON "
|
||||
"locations(sourceId, locationKind)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, "
|
||||
"directoryId INTEGER, sourceName TEXT)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_sources_directoryId_sourceName "
|
||||
"ON sources(directoryId, sourceName)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS directories(directoryId INTEGER PRIMARY "
|
||||
"KEY, directoryPath TEXT)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_directories_directoryPath ON "
|
||||
"directories(directoryPath)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(
|
||||
Eq("CREATE TABLE IF NOT EXISTS projectParts(projectPartId INTEGER PRIMARY "
|
||||
"KEY, projectPartName TEXT, toolChainArguments TEXT, compilerMacros "
|
||||
"TEXT, systemIncludeSearchPaths TEXT, projectIncludeSearchPaths TEXT, "
|
||||
"language INTEGER, languageVersion INTEGER, languageExtension INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName "
|
||||
"ON projectParts(projectPartName)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsFiles(projectPartId INTEGER, "
|
||||
"sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER, "
|
||||
"hasMissingIncludes INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId ON projectPartsFiles(sourceId, projectPartId)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId ON projectPartsFiles(projectPartId)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)")));
|
||||
EXPECT_CALL(
|
||||
mockDatabase,
|
||||
execute(
|
||||
Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsFiles_sourceId_projectPartId "
|
||||
"ON projectPartsFiles(sourceId, projectPartId)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsFiles_projectPartId ON "
|
||||
"projectPartsFiles(projectPartId)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, "
|
||||
"sourceId INTEGER, macroName TEXT)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON "
|
||||
"usedMacros(sourceId, macroName)")));
|
||||
EXPECT_CALL(
|
||||
mockDatabase,
|
||||
execute(
|
||||
Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)")));
|
||||
EXPECT_CALL(
|
||||
mockDatabase,
|
||||
execute(Eq(
|
||||
"CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, "
|
||||
"lastModified INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)")));
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, systemPchPath TEXT, systemPchBuildTime INTEGER)")));
|
||||
"lastModified INTEGER, indexingTimeStamp INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, "
|
||||
"dependencySourceId INTEGER)")));
|
||||
EXPECT_CALL(
|
||||
mockDatabase,
|
||||
execute(
|
||||
Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON "
|
||||
"sourceDependencies(sourceId, dependencySourceId)")));
|
||||
EXPECT_CALL(
|
||||
mockDatabase,
|
||||
execute(
|
||||
Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_dependencySourceId_sourceId ON "
|
||||
"sourceDependencies(dependencySourceId, sourceId)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER "
|
||||
"PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, "
|
||||
"systemPchPath TEXT, systemPchBuildTime INTEGER)")));
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsHeaders(projectPartId INTEGER, "
|
||||
"sourceId INTEGER)")));
|
||||
@@ -271,7 +330,7 @@ TEST_F(RefactoringDatabaseInitializer, DontCreateIfAlreadyInitialized)
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))).Times(0);
|
||||
EXPECT_CALL(mockDatabase,
|
||||
execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, "
|
||||
"size INTEGER, lastModified INTEGER, isInPrecompiledHeader INTEGER)")))
|
||||
"size INTEGER, lastModified INTEGER, indexingTimeStamp INTEGER)")))
|
||||
.Times(0);
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)"))).Times(0);
|
||||
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)"))).Times(0);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "mockbuilddependenciesstorage.h"
|
||||
#include "mockclangpathwatcher.h"
|
||||
#include "mockfilepathcaching.h"
|
||||
#include "mockmodifiedtimechecker.h"
|
||||
#include "mockprecompiledheaderstorage.h"
|
||||
#include "mockprojectpartsstorage.h"
|
||||
#include "mocksqlitetransactionbackend.h"
|
||||
@@ -113,7 +114,12 @@ protected:
|
||||
.WillByDefault(Return(artefact));
|
||||
ON_CALL(mockBuildDependenciesStorage, fetchLowestLastModifiedTime(A<FilePathId>())).WillByDefault(Return(-1));
|
||||
ON_CALL(mockCollector, collectSymbols()).WillByDefault(Return(true));
|
||||
|
||||
ON_CALL(mockSymbolStorage, fetchDependentSourceIds(sourceFileIds))
|
||||
.WillByDefault(Return(sourceFileIds));
|
||||
ON_CALL(mockSymbolStorage, fetchDependentSourceIds(ElementsAre(sourceFileIds[0])))
|
||||
.WillByDefault(Return(FilePathIds{sourceFileIds[0]}));
|
||||
ON_CALL(mockSymbolStorage, fetchDependentSourceIds(ElementsAre(main1PathId)))
|
||||
.WillByDefault(Return(FilePathIds{main1PathId}));
|
||||
mockCollector.setIsUsed(false);
|
||||
|
||||
generatedFiles.update(unsaved);
|
||||
@@ -230,6 +236,10 @@ protected:
|
||||
Utils::Language::Cxx,
|
||||
Utils::LanguageVersion::CXX14,
|
||||
Utils::LanguageExtension::None};
|
||||
ClangBackEnd::SourceTimeStamps dependentSourceTimeStamps1{{1, 32}};
|
||||
ClangBackEnd::SourceTimeStamps dependentSourceTimeStamps2{{2, 35}};
|
||||
ClangBackEnd::FileStatuses fileStatuses1{{1, 0, 32}};
|
||||
ClangBackEnd::FileStatuses fileStatuses2{{2, 0, 35}};
|
||||
Utils::optional<ClangBackEnd::ProjectPartArtefact > nullArtefact;
|
||||
ClangBackEnd::ProjectPartPch projectPartPch{74, "/path/to/pch", 4};
|
||||
NiceMock<MockSqliteTransactionBackend> mockSqliteTransactionBackend;
|
||||
@@ -243,6 +253,7 @@ protected:
|
||||
Manager collectorManger{generatedFiles};
|
||||
NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback;
|
||||
ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()};
|
||||
NiceMock<MockSourceTimeStampsModifiedTimeChecker> mockModifiedTimeChecker;
|
||||
ClangBackEnd::SymbolIndexer indexer{indexerQueue,
|
||||
mockSymbolStorage,
|
||||
mockBuildDependenciesStorage,
|
||||
@@ -251,7 +262,8 @@ protected:
|
||||
filePathCache,
|
||||
fileStatusCache,
|
||||
mockSqliteTransactionBackend,
|
||||
mockProjectPartsStorage};
|
||||
mockProjectPartsStorage,
|
||||
mockModifiedTimeChecker};
|
||||
SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter};
|
||||
Scheduler indexerScheduler{collectorManger,
|
||||
indexerQueue,
|
||||
@@ -493,6 +505,58 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderButGetsAnErrorForCollectingS
|
||||
indexer.updateProjectParts({projectPart1});
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, UpdateProjectPartsFetchIncludedIndexingTimeStamps)
|
||||
{
|
||||
InSequence s;
|
||||
ProjectPartContainer projectPart{1,
|
||||
{"-Wno-pragma-once-outside-header"},
|
||||
{{"BAR", "1", 1}, {"FOO", "1", 2}},
|
||||
Utils::clone(systemIncludeSearchPaths),
|
||||
Utils::clone(projectIncludeSearchPaths),
|
||||
{header1PathId},
|
||||
{main1PathId, main2PathId},
|
||||
Utils::Language::Cxx,
|
||||
Utils::LanguageVersion::CXX14,
|
||||
Utils::LanguageExtension::None};
|
||||
|
||||
EXPECT_CALL(mockSymbolStorage, fetchIncludedIndexingTimeStamps(Eq(main1PathId)))
|
||||
.WillOnce(Return(dependentSourceTimeStamps1));
|
||||
EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(dependentSourceTimeStamps1));
|
||||
EXPECT_CALL(mockSymbolStorage, fetchIncludedIndexingTimeStamps(Eq(main2PathId)))
|
||||
.WillOnce(Return(dependentSourceTimeStamps2));
|
||||
EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(dependentSourceTimeStamps2));
|
||||
EXPECT_CALL(mockCollector, fileStatuses()).WillRepeatedly(ReturnRef(fileStatuses1));
|
||||
EXPECT_CALL(mockSymbolStorage, insertOrUpdateIndexingTimeStamps(fileStatuses1));
|
||||
EXPECT_CALL(mockCollector, fileStatuses()).WillRepeatedly(ReturnRef(fileStatuses2));
|
||||
EXPECT_CALL(mockSymbolStorage, insertOrUpdateIndexingTimeStamps(fileStatuses2));
|
||||
|
||||
indexer.updateProjectParts({projectPart});
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, DependentSourceAreNotUpToDate)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(_)).WillOnce(Return(false));
|
||||
EXPECT_CALL(mockCollector, setFile(main1PathId, _));
|
||||
EXPECT_CALL(mockCollector, collectSymbols()).WillOnce(Return(true));
|
||||
EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations));
|
||||
|
||||
indexer.updateProjectParts({projectPart1});
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, DependentSourceAreUpToDate)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(_)).WillOnce(Return(true));
|
||||
EXPECT_CALL(mockCollector, setFile(main1PathId, _)).Times(0);
|
||||
EXPECT_CALL(mockCollector, collectSymbols()).Times(0);
|
||||
EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)).Times(0);
|
||||
|
||||
indexer.updateProjectParts({projectPart1});
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, CallSetNotifier)
|
||||
{
|
||||
EXPECT_CALL(mockPathWatcher, setNotifier(_));
|
||||
@@ -505,7 +569,8 @@ TEST_F(SymbolIndexer, CallSetNotifier)
|
||||
filePathCache,
|
||||
fileStatusCache,
|
||||
mockSqliteTransactionBackend,
|
||||
mockProjectPartsStorage};
|
||||
mockProjectPartsStorage,
|
||||
mockModifiedTimeChecker};
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, PathChangedCallsFetchProjectPartArtefactInStorage)
|
||||
@@ -516,6 +581,54 @@ TEST_F(SymbolIndexer, PathChangedCallsFetchProjectPartArtefactInStorage)
|
||||
indexer.pathsChanged(sourceFileIds);
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, PathChangedCallsFetchSourcePathIds)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockSymbolStorage, fetchDependentSourceIds(sourceFileIds))
|
||||
.WillOnce(Return(FilePathIds{2, 6, 5}));
|
||||
EXPECT_CALL(mockProjectPartsStorage, fetchProjectPartArtefact(FilePathId{2}));
|
||||
EXPECT_CALL(mockProjectPartsStorage, fetchProjectPartArtefact(FilePathId{6}));
|
||||
EXPECT_CALL(mockProjectPartsStorage, fetchProjectPartArtefact(FilePathId{5}));
|
||||
|
||||
indexer.pathsChanged(sourceFileIds);
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, PathChangedFetchIncludedIndexingTimeStamps)
|
||||
{
|
||||
InSequence s;
|
||||
ProjectPartContainer projectPart{1,
|
||||
{"-Wno-pragma-once-outside-header"},
|
||||
{{"BAR", "1", 1}, {"FOO", "1", 2}},
|
||||
Utils::clone(systemIncludeSearchPaths),
|
||||
Utils::clone(projectIncludeSearchPaths),
|
||||
{header1PathId},
|
||||
{main1PathId, main2PathId},
|
||||
Utils::Language::Cxx,
|
||||
Utils::LanguageVersion::CXX14,
|
||||
Utils::LanguageExtension::None};
|
||||
|
||||
EXPECT_CALL(mockSymbolStorage, fetchDependentSourceIds(_)).WillOnce(Return(FilePathIds{1, 2}));
|
||||
EXPECT_CALL(mockSymbolStorage, fetchIncludedIndexingTimeStamps(Eq(1)))
|
||||
.WillOnce(Return(dependentSourceTimeStamps1));
|
||||
EXPECT_CALL(mockSymbolStorage, fetchIncludedIndexingTimeStamps(Eq(2)))
|
||||
.WillOnce(Return(dependentSourceTimeStamps2));
|
||||
EXPECT_CALL(mockCollector, fileStatuses()).WillOnce(ReturnRef(fileStatuses1));
|
||||
EXPECT_CALL(mockSymbolStorage, insertOrUpdateIndexingTimeStamps(fileStatuses1));
|
||||
EXPECT_CALL(mockCollector, fileStatuses()).WillOnce(ReturnRef(fileStatuses2));
|
||||
EXPECT_CALL(mockSymbolStorage, insertOrUpdateIndexingTimeStamps(fileStatuses2));
|
||||
|
||||
indexer.pathsChanged({1, 3});
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, PathChangedFetchesDependentSourceIdsFromStorage)
|
||||
{
|
||||
EXPECT_CALL(mockProjectPartsStorage, fetchProjectPartArtefact(sourceFileIds[0]));
|
||||
EXPECT_CALL(mockProjectPartsStorage, fetchProjectPartArtefact(sourceFileIds[1]));
|
||||
|
||||
indexer.pathsChanged(sourceFileIds);
|
||||
}
|
||||
|
||||
TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder)
|
||||
{
|
||||
InSequence s;
|
||||
@@ -797,6 +910,7 @@ TEST_F(SymbolIndexer, PathsChangedUpdatesFileStatusCache)
|
||||
auto sourceId = filePathId(TESTDATA_DIR "/symbolindexer_pathChanged.cpp");
|
||||
auto oldLastModified = fileStatusCache.lastModifiedTime(sourceId);
|
||||
touchFile(sourceId);
|
||||
ON_CALL(mockSymbolStorage, fetchDependentSourceIds(_)).WillByDefault(Return(FilePathIds{sourceId}));
|
||||
|
||||
indexer.pathsChanged({sourceId});
|
||||
|
||||
|
||||
@@ -28,17 +28,22 @@
|
||||
#include "mockfilepathcaching.h"
|
||||
#include "mocksqlitedatabase.h"
|
||||
|
||||
#include <symbolstorage.h>
|
||||
#include <builddependenciesstorage.h>
|
||||
#include <refactoringdatabaseinitializer.h>
|
||||
#include <sqlitedatabase.h>
|
||||
#include <sqlitereadstatement.h>
|
||||
#include <sqlitewritestatement.h>
|
||||
#include <symbolstorage.h>
|
||||
|
||||
#include <utils/optional.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using ClangBackEnd::FilePathCachingInterface;
|
||||
using ClangBackEnd::FilePathId;
|
||||
using ClangBackEnd::SourceLocationEntries;
|
||||
using ClangBackEnd::SourceLocationEntry;
|
||||
using ClangBackEnd::SourceLocationKind;
|
||||
using ClangBackEnd::SourceTimeStamp;
|
||||
using ClangBackEnd::SymbolEntries;
|
||||
using ClangBackEnd::SymbolEntry;
|
||||
using ClangBackEnd::SymbolIndex;
|
||||
@@ -64,6 +69,10 @@ protected:
|
||||
MockSqliteWriteStatement &insertNewLocationsInLocationsStatement = storage.insertNewLocationsInLocationsStatement;
|
||||
MockSqliteWriteStatement &deleteNewSymbolsTableStatement = storage.deleteNewSymbolsTableStatement;
|
||||
MockSqliteWriteStatement &deleteNewLocationsTableStatement = storage.deleteNewLocationsTableStatement;
|
||||
MockSqliteWriteStatement &inserOrUpdateIndexingTimesStampStatement = storage.inserOrUpdateIndexingTimesStampStatement;
|
||||
MockSqliteReadStatement &fetchIndexingTimeStampsStatement = storage.fetchIndexingTimeStampsStatement;
|
||||
MockSqliteReadStatement &fetchIncludedIndexingTimeStampsStatement = storage.fetchIncludedIndexingTimeStampsStatement;
|
||||
MockSqliteReadStatement &fetchDependentSourceIdsStatement = storage.fetchDependentSourceIdsStatement;
|
||||
SymbolEntries symbolEntries{{1, {"functionUSR", "function", SymbolKind::Function}},
|
||||
{2, {"function2USR", "function2", SymbolKind::Function}}};
|
||||
SourceLocationEntries sourceLocations{{1, 3, {42, 23}, SourceLocationKind::Declaration},
|
||||
@@ -183,5 +192,145 @@ TEST_F(SymbolStorage, AddTablesInConstructor)
|
||||
Storage storage{mockDatabase};
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorage, FetchIndexingTimeStampsIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockDatabase, deferredBegin());
|
||||
EXPECT_CALL(fetchIndexingTimeStampsStatement, valuesReturnSourceTimeStamps(1024))
|
||||
.WillOnce(Throw(Sqlite::StatementIsBusy{""}));
|
||||
EXPECT_CALL(mockDatabase, rollback());
|
||||
EXPECT_CALL(mockDatabase, deferredBegin());
|
||||
EXPECT_CALL(fetchIndexingTimeStampsStatement, valuesReturnSourceTimeStamps(1024));
|
||||
EXPECT_CALL(mockDatabase, commit());
|
||||
|
||||
storage.fetchIndexingTimeStamps();
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorage, InsertIndexingTimeStamp)
|
||||
{
|
||||
ClangBackEnd::FileStatuses fileStatuses{{1, 0, 34}, {2, 0, 37}};
|
||||
|
||||
EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq<int>(1), TypedEq<int>(34)));
|
||||
EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq<int>(2), TypedEq<int>(37)));
|
||||
|
||||
storage.insertOrUpdateIndexingTimeStamps(fileStatuses);
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorage, InsertIndexingTimeStampsIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockDatabase, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""}));
|
||||
EXPECT_CALL(mockDatabase, immediateBegin());
|
||||
EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq<int>(1), TypedEq<int>(34)));
|
||||
EXPECT_CALL(inserOrUpdateIndexingTimesStampStatement, write(TypedEq<int>(2), TypedEq<int>(34)));
|
||||
EXPECT_CALL(mockDatabase, commit());
|
||||
|
||||
storage.insertOrUpdateIndexingTimeStamps({1, 2}, 34);
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorage, FetchIncludedIndexingTimeStampsIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockDatabase, deferredBegin());
|
||||
EXPECT_CALL(fetchIncludedIndexingTimeStampsStatement,
|
||||
valuesReturnSourceTimeStamps(1024, TypedEq<int>(1)))
|
||||
.WillOnce(Throw(Sqlite::StatementIsBusy{""}));
|
||||
EXPECT_CALL(mockDatabase, rollback());
|
||||
EXPECT_CALL(mockDatabase, deferredBegin());
|
||||
EXPECT_CALL(fetchIncludedIndexingTimeStampsStatement,
|
||||
valuesReturnSourceTimeStamps(1024, TypedEq<int>(1)));
|
||||
EXPECT_CALL(mockDatabase, commit());
|
||||
|
||||
storage.fetchIncludedIndexingTimeStamps(1);
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorage, FetchDependentSourceIdsIsBusy)
|
||||
{
|
||||
InSequence s;
|
||||
|
||||
EXPECT_CALL(mockDatabase, deferredBegin());
|
||||
EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq<int>(3)));
|
||||
EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq<int>(2)))
|
||||
.WillOnce(Throw(Sqlite::StatementIsBusy{""}));
|
||||
EXPECT_CALL(mockDatabase, rollback());
|
||||
EXPECT_CALL(mockDatabase, deferredBegin());
|
||||
EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq<int>(3)));
|
||||
EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq<int>(2)));
|
||||
EXPECT_CALL(fetchDependentSourceIdsStatement, valuesReturnFilePathIds(1024, TypedEq<int>(7)));
|
||||
EXPECT_CALL(mockDatabase, commit());
|
||||
|
||||
storage.fetchDependentSourceIds({3, 2, 7});
|
||||
}
|
||||
|
||||
class SymbolStorageSlow : public testing::Test
|
||||
{
|
||||
protected:
|
||||
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
||||
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
|
||||
ClangBackEnd::SymbolStorage<> storage{database};
|
||||
ClangBackEnd::BuildDependenciesStorage<> buildDependenciesStorage{database};
|
||||
};
|
||||
|
||||
TEST_F(SymbolStorageSlow, InsertIndexingTimeStamps)
|
||||
{
|
||||
storage.insertOrUpdateIndexingTimeStamps({1, 2}, 34);
|
||||
|
||||
ASSERT_THAT(storage.fetchIndexingTimeStamps(),
|
||||
ElementsAre(SourceTimeStamp{1, 34}, SourceTimeStamp{2, 34}));
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorageSlow, UpdateIndexingTimeStamps)
|
||||
{
|
||||
storage.insertOrUpdateIndexingTimeStamps({1, 2}, 34);
|
||||
|
||||
storage.insertOrUpdateIndexingTimeStamps({1}, 37);
|
||||
|
||||
ASSERT_THAT(storage.fetchIndexingTimeStamps(),
|
||||
ElementsAre(SourceTimeStamp{1, 37}, SourceTimeStamp{2, 34}));
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorageSlow, InsertIndexingTimeStamp)
|
||||
{
|
||||
storage.insertOrUpdateIndexingTimeStamps({{1, 0, 34}, {2, 0, 37}});
|
||||
|
||||
ASSERT_THAT(storage.fetchIndexingTimeStamps(),
|
||||
ElementsAre(SourceTimeStamp{1, 34}, SourceTimeStamp{2, 37}));
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorageSlow, UpdateIndexingTimeStamp)
|
||||
{
|
||||
storage.insertOrUpdateIndexingTimeStamps({{1, 0, 34}, {2, 0, 34}});
|
||||
|
||||
storage.insertOrUpdateIndexingTimeStamps({{2, 0, 37}});
|
||||
|
||||
ASSERT_THAT(storage.fetchIndexingTimeStamps(),
|
||||
ElementsAre(SourceTimeStamp{1, 34}, SourceTimeStamp{2, 37}));
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorageSlow, FetchIncludedIndexingTimeStamps)
|
||||
{
|
||||
storage.insertOrUpdateIndexingTimeStamps({1, 2, 3, 4, 5}, 34);
|
||||
buildDependenciesStorage.insertOrUpdateSourceDependencies({{1, 2}, {1, 3}, {2, 3}, {3, 4}, {5, 3}});
|
||||
|
||||
auto timeStamps = storage.fetchIncludedIndexingTimeStamps(1);
|
||||
|
||||
ASSERT_THAT(timeStamps,
|
||||
ElementsAre(SourceTimeStamp{1, 34},
|
||||
SourceTimeStamp{2, 34},
|
||||
SourceTimeStamp{3, 34},
|
||||
SourceTimeStamp{4, 34}));
|
||||
}
|
||||
|
||||
TEST_F(SymbolStorageSlow, FetchDependentSourceIds)
|
||||
{
|
||||
buildDependenciesStorage.insertOrUpdateSourceDependencies(
|
||||
{{1, 2}, {1, 3}, {2, 3}, {4, 2}, {5, 6}, {7, 6}});
|
||||
|
||||
auto sourceIds = storage.fetchDependentSourceIds({3, 2, 7});
|
||||
|
||||
ASSERT_THAT(sourceIds, ElementsAre(FilePathId{1}, FilePathId{4}, FilePathId{7}));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -113,7 +113,7 @@ TEST_F(TranslationUnitUpdaterSlowTest, NotUpdatingParseTimePointForReparseOnly)
|
||||
ASSERT_FALSE(result.hasParsed());
|
||||
}
|
||||
|
||||
TEST_F(TranslationUnitUpdaterSlowTest, UpdatesDependendOnFilesOnParse)
|
||||
TEST_F(TranslationUnitUpdaterSlowTest, UpdatesDependentOnFilesOnParse)
|
||||
{
|
||||
::TranslationUnitUpdater updater = createUpdater(createInput());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user