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:
Marco Bubke
2019-03-21 17:55:24 +01:00
parent 7595c9f305
commit 56b01f7463
37 changed files with 736 additions and 120 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -29,6 +29,7 @@
namespace ClangBackEnd {
template<typename SourceEntries = ::ClangBackEnd::SourceEntries>
class ModifiedTimeCheckerInterface
{
public:

View File

@@ -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

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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,

View File

@@ -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;
};

View File

@@ -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 += \

View File

@@ -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();
}

View File

@@ -65,7 +65,7 @@ ProjectPartContainers ProjectPartsManager::update(ProjectPartContainers &&projec
}
m_projectPartsStorage.updateProjectParts(updatedProjectParts);
m_projectPartsStorage.resetIndexingTimeStamps(updatedProjectParts);
m_precompiledHeaderStorage.deleteProjectPrecompiledHeaders(
toProjectPartIds(updatedProjectParts));

View File

@@ -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();
}
};

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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

View File

@@ -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;

View File

@@ -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,

View File

@@ -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();

View File

@@ -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)

View File

@@ -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) {

View File

@@ -165,7 +165,7 @@ class UpdateProjectPartsMessage;
class DocumentsChangedMessage;
class DocumentVisibilityChangedMessage;
class FilePath;
template <char WindowsSlash>
template<char WindowsSlash>
class AbstractFilePathView;
using FilePathView = AbstractFilePathView<'/'>;
using NativeFilePathView = AbstractFilePathView<'\\'>;
@@ -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);

View File

@@ -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));
};

View File

@@ -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 &());
};

View File

@@ -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)

View File

@@ -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&);

View File

@@ -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));
};

View File

@@ -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},

View File

@@ -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});
}

View File

@@ -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

View File

@@ -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);

View File

@@ -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});

View File

@@ -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

View File

@@ -113,7 +113,7 @@ TEST_F(TranslationUnitUpdaterSlowTest, NotUpdatingParseTimePointForReparseOnly)
ASSERT_FALSE(result.hasParsed());
}
TEST_F(TranslationUnitUpdaterSlowTest, UpdatesDependendOnFilesOnParse)
TEST_F(TranslationUnitUpdaterSlowTest, UpdatesDependentOnFilesOnParse)
{
::TranslationUnitUpdater updater = createUpdater(createInput());