Clang: On the road to update and preprocessor support

This patch has grown in a quite big change set and it is really hard to
divide it in different parts.
V2::ProjectPartContainer is now using FileIds instead of file paths. This
cleans code up because it is a big step in the direction that internally
only file ids are used. But it is depending on the file cache, so the
file cache has to be provided as an argument. There is now an interface for
transactions too which are ease the testing of them and enables the support
of preprocessor. It adds macros as symbols and is saving used macros. The
used macro support is enabling update improvements because only if a
changed macro is used it needs to be recompiled. This is still in flux
and can be changed in later patches.

Change-Id: I492a2c9af1201d40fdd9f46a0045f7878bbbaa3d
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Marco Bubke
2018-01-22 14:21:01 +01:00
parent 3d2db474a4
commit 0f8befacd3
70 changed files with 1543 additions and 531 deletions

View File

@@ -39,8 +39,6 @@ namespace ClangBackEnd {
template <typename StatementFactory>
class FilePathStorage
{
using DeferredTransaction = Sqlite::DeferredTransaction<typename StatementFactory::DatabaseType>;
using ImmediateTransaction = Sqlite::ImmediateTransaction<typename StatementFactory::DatabaseType>;
using ReadStatement = typename StatementFactory::ReadStatementType;
using WriteStatement = typename StatementFactory::WriteStatementType;
using Database = typename StatementFactory::DatabaseType;
@@ -52,7 +50,7 @@ public:
int fetchDirectoryId(Utils::SmallStringView directoryPath)
try {
DeferredTransaction transaction{m_statementFactory.database};
Sqlite::DeferredTransaction transaction{m_statementFactory.database};
Utils::optional<int> optionalDirectoryId = readDirectoryId(directoryPath);
@@ -88,7 +86,7 @@ public:
Utils::PathString fetchDirectoryPath(int directoryPathId)
{
DeferredTransaction transaction{m_statementFactory.database};
Sqlite::DeferredTransaction transaction{m_statementFactory.database};
ReadStatement &statement = m_statementFactory.selectDirectoryPathFromDirectoriesByDirectoryId;
@@ -104,7 +102,7 @@ public:
std::vector<Sources::Directory> fetchAllDirectories()
{
DeferredTransaction transaction{m_statementFactory.database};
Sqlite::DeferredTransaction transaction{m_statementFactory.database};
ReadStatement &statement = m_statementFactory.selectAllDirectories;
@@ -117,7 +115,7 @@ public:
int fetchSourceId(int directoryId, Utils::SmallStringView sourceName)
try {
DeferredTransaction transaction{m_statementFactory.database};
Sqlite::DeferredTransaction transaction{m_statementFactory.database};
Utils::optional<int> optionalSourceId = readSourceId(directoryId, sourceName);
@@ -153,7 +151,7 @@ public:
Utils::SmallString fetchSourceName(int sourceId)
{
DeferredTransaction transaction{m_statementFactory.database};
Sqlite::DeferredTransaction transaction{m_statementFactory.database};
ReadStatement &statement = m_statementFactory.selectSourceNameFromSourcesBySourceId;
@@ -169,7 +167,7 @@ public:
std::vector<Sources::Source> fetchAllSources()
{
DeferredTransaction transaction{m_statementFactory.database};
Sqlite::DeferredTransaction transaction{m_statementFactory.database};
ReadStatement &statement = m_statementFactory.selectAllSources;

View File

@@ -33,8 +33,8 @@ QDebug operator<<(QDebug debug, const ProjectPartContainer &container)
debug.nospace() << "ProjectPartContainer("
<< container.projectPartId() << ","
<< container.arguments() << ", "
<< container.headerPaths() << ", "
<< container.sourcePaths()
<< container.headerPathIds() << ", "
<< container.sourcePathIds()
<< ")";
return debug;

View File

@@ -27,6 +27,8 @@
#include "clangsupport_global.h"
#include <filepathid.h>
#include <utils/smallstringio.h>
namespace ClangBackEnd {
@@ -38,12 +40,12 @@ public:
ProjectPartContainer() = default;
ProjectPartContainer(Utils::SmallString &&projectPartId,
Utils::SmallStringVector &&arguments,
Utils::PathStringVector &&headerPaths,
Utils::PathStringVector &&sourcePaths)
FilePathIds &&headerPathIds,
FilePathIds &&sourcePathIds)
: m_projectPartId(std::move(projectPartId)),
m_arguments(std::move(arguments)),
m_headerPaths(std::move(headerPaths)),
m_sourcePaths(std::move(sourcePaths))
m_headerPathIds(std::move(headerPathIds)),
m_sourcePathIds(std::move(sourcePathIds))
{
}
@@ -57,22 +59,27 @@ public:
return m_arguments;
}
const Utils::PathStringVector &sourcePaths() const
Utils::SmallStringVector takeArguments()
{
return m_sourcePaths;
return std::move(m_arguments);
}
const Utils::PathStringVector &headerPaths() const
const FilePathIds &sourcePathIds() const
{
return m_headerPaths;
return m_sourcePathIds;
}
const FilePathIds &headerPathIds() const
{
return m_headerPathIds;
}
friend QDataStream &operator<<(QDataStream &out, const ProjectPartContainer &container)
{
out << container.m_projectPartId;
out << container.m_arguments;
out << container.m_headerPaths;
out << container.m_sourcePaths;
out << container.m_headerPathIds;
out << container.m_sourcePathIds;
return out;
}
@@ -81,8 +88,8 @@ public:
{
in >> container.m_projectPartId;
in >> container.m_arguments;
in >> container.m_headerPaths;
in >> container.m_sourcePaths;
in >> container.m_headerPathIds;
in >> container.m_sourcePathIds;
return in;
}
@@ -91,29 +98,26 @@ public:
{
return first.m_projectPartId == second.m_projectPartId
&& first.m_arguments == second.m_arguments
&& first.m_headerPaths == second.m_headerPaths
&& first.m_sourcePaths == second.m_sourcePaths;
&& first.m_headerPathIds == second.m_headerPathIds
&& first.m_sourcePathIds == second.m_sourcePathIds;
}
friend bool operator<(const ProjectPartContainer &first, const ProjectPartContainer &second)
{
return std::tie(first.m_projectPartId, first.m_arguments, first.m_headerPaths, first.m_sourcePaths)
< std::tie(second.m_projectPartId, second.m_arguments, second.m_headerPaths, second.m_sourcePaths);
return std::tie(first.m_projectPartId, first.m_arguments, first.m_headerPathIds, first.m_sourcePathIds)
< std::tie(second.m_projectPartId, second.m_arguments, second.m_headerPathIds, second.m_sourcePathIds);
}
ProjectPartContainer clone() const
{
return ProjectPartContainer(m_projectPartId.clone(),
m_arguments.clone(),
m_headerPaths.clone(),
m_sourcePaths.clone());
return *this;
}
private:
Utils::SmallString m_projectPartId;
Utils::SmallStringVector m_arguments;
Utils::PathStringVector m_headerPaths;
Utils::PathStringVector m_sourcePaths;
FilePathIds m_headerPathIds;
FilePathIds m_sourcePathIds;
};
using ProjectPartContainers = std::vector<ProjectPartContainer>;

View File

@@ -39,13 +39,14 @@ public:
RefactoringDatabaseInitializer(DatabaseType &database)
: database(database)
{
Sqlite::ImmediateTransaction<DatabaseType> transaction{database};
Sqlite::ImmediateTransaction transaction{database};
createSymbolsTable();
createLocationsTable();
createSourcesTable();
createDirectoriesTable();
createProjectPartsTable();
createprojectPartsSourcesTable();
transaction.commit();
}
@@ -83,10 +84,10 @@ public:
table.setUseIfNotExists(true);
table.setName("sources");
table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey);
table.addColumn("directoryId", Sqlite::ColumnType::Integer);
const Sqlite::Column &directoryIdColumn = table.addColumn("directoryId", Sqlite::ColumnType::Integer);
const Sqlite::Column &sourceNameColumn = table.addColumn("sourceName", Sqlite::ColumnType::Text);
table.addColumn("sourceType", Sqlite::ColumnType::Integer);
table.addIndex({sourceNameColumn});
table.addIndex({directoryIdColumn, sourceNameColumn});
table.initialize(database);
}
@@ -116,6 +117,19 @@ public:
table.initialize(database);
}
void createprojectPartsSourcesTable()
{
Sqlite::Table table;
table.setUseIfNotExists(true);
table.setName("projectPartsSources");
const Sqlite::Column &projectPartIdColumn = table.addColumn("projectPartId", Sqlite::ColumnType::Integer);
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
table.addIndex({sourceIdColumn, projectPartIdColumn});
table.addIndex({projectPartIdColumn});
table.initialize(database);
}
public:
DatabaseType &database;
};

View File

@@ -116,7 +116,7 @@ void Database::execute(Utils::SmallStringView sqlStatement)
void Database::initializeTables()
{
ImmediateTransaction<Database> transaction(*this);
ImmediateTransaction transaction(*this);
for (Table &table : m_sqliteTables)
table.initialize(*this);

View File

@@ -28,6 +28,7 @@
#include "sqlitedatabasebackend.h"
#include "sqliteglobal.h"
#include "sqlitetable.h"
#include "sqlitetransaction.h"
#include <utils/smallstring.h>
@@ -36,10 +37,9 @@
namespace Sqlite {
class SQLITE_EXPORT Database
class SQLITE_EXPORT Database final : public TransactionInterface
{
template <typename Database>
friend class AbstractTransaction;
friend class Statement;
friend class Backend;
@@ -97,6 +97,36 @@ public:
return m_databaseBackend.totalChangesCount();
}
void deferredBegin()
{
m_databaseMutex.lock();
execute("BEGIN");
}
void immediateBegin()
{
m_databaseMutex.lock();
execute("BEGIN IMMEDIATE");
}
void exclusiveBegin()
{
m_databaseMutex.lock();
execute("BEGIN EXCLUSIVE");
}
void commit()
{
execute("COMMIT");
m_databaseMutex.unlock();
}
void rollback()
{
execute("ROLLBACK");
m_databaseMutex.unlock();
}
private:
void initializeTables();
std::mutex &databaseMutex() { return m_databaseMutex; }

View File

@@ -31,4 +31,8 @@
namespace Sqlite {
TransactionInterface::~TransactionInterface()
{
}
} // namespace Sqlite

View File

@@ -34,65 +34,77 @@ namespace Sqlite {
class DatabaseBackend;
class Database;
template <typename Database>
class TransactionInterface
{
public:
TransactionInterface() = default;
virtual ~TransactionInterface();
TransactionInterface(const TransactionInterface &) = delete;
TransactionInterface &operator=(const TransactionInterface &) = delete;
virtual void deferredBegin() = 0;
virtual void immediateBegin() = 0;
virtual void exclusiveBegin() = 0;
virtual void commit() = 0;
virtual void rollback() = 0;
};
class AbstractTransaction
{
public:
~AbstractTransaction()
{
if (!m_isAlreadyCommited)
m_database.execute("ROLLBACK");
m_interface.rollback();
}
AbstractTransaction(const AbstractTransaction &) = delete;
AbstractTransaction &operator=(const AbstractTransaction &) = delete;
void commit()
{
m_database.execute("COMMIT");
m_interface.commit();
m_isAlreadyCommited = true;
}
protected:
AbstractTransaction(Database &database)
: m_databaseLock(database.databaseMutex()),
m_database(database)
AbstractTransaction(TransactionInterface &interface)
: m_interface(interface)
{
}
private:
std::lock_guard<typename Database::MutexType> m_databaseLock;
Database &m_database;
TransactionInterface &m_interface;
bool m_isAlreadyCommited = false;
};
template <typename Database>
class DeferredTransaction final : public AbstractTransaction<Database>
class DeferredTransaction final : public AbstractTransaction
{
public:
DeferredTransaction(Database &database)
: AbstractTransaction<Database>(database)
DeferredTransaction(TransactionInterface &interface)
: AbstractTransaction(interface)
{
database.execute("BEGIN");
interface.deferredBegin();
}
};
template <typename Database>
class ImmediateTransaction final : public AbstractTransaction<Database>
class ImmediateTransaction final : public AbstractTransaction
{
public:
ImmediateTransaction(Database &database)
: AbstractTransaction<Database>(database)
ImmediateTransaction(TransactionInterface &interface)
: AbstractTransaction(interface)
{
database.execute("BEGIN IMMEDIATE");
interface.immediateBegin();
}
};
template <typename Database>
class ExclusiveTransaction final : public AbstractTransaction<Database>
class ExclusiveTransaction final : public AbstractTransaction
{
public:
ExclusiveTransaction(Database &database)
: AbstractTransaction<Database>(database)
ExclusiveTransaction(TransactionInterface &interface)
: AbstractTransaction(interface)
{
database.execute("BEGIN EXCLUSIVE");
interface.exclusiveBegin();
}
};

View File

@@ -29,6 +29,10 @@
#include "pchmanagerclient.h"
#include "qtcreatorprojectupdater.h"
#include <filepathcaching.h>
#include <refactoringdatabaseinitializer.h>
#include <sqlitedatabase.h>
#include <coreplugin/icore.h>
#include <extensionsystem/pluginmanager.h>
@@ -50,9 +54,14 @@ QString backendProcessPath()
class ClangPchManagerPluginData
{
public:
Sqlite::Database database{Utils::PathString{Core::ICore::userResourcePath() + "/symbol-experimental-v1.db"}};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
PchManagerClient pchManagerClient;
PchManagerConnectionClient connectionClient{&pchManagerClient};
QtCreatorProjectUpdater<PchManagerProjectUpdater> projectUpdate{connectionClient.serverProxy(), pchManagerClient};
QtCreatorProjectUpdater<PchManagerProjectUpdater> projectUpdate{connectionClient.serverProxy(),
pchManagerClient,
filePathCache};
};
std::unique_ptr<ClangPchManagerPluginData> ClangPchManagerPlugin::d;

View File

@@ -30,8 +30,9 @@
namespace ClangPchManager {
PchManagerProjectUpdater::PchManagerProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
PchManagerClient &client)
: ProjectUpdater(server),
PchManagerClient &client,
ClangBackEnd::FilePathCachingInterface &filePathCache)
: ProjectUpdater(server, filePathCache),
m_client(client)
{
}

View File

@@ -33,7 +33,8 @@ class PchManagerProjectUpdater : public ProjectUpdater
{
public:
PchManagerProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
PchManagerClient &client);
PchManagerClient &client,
ClangBackEnd::FilePathCachingInterface &filePathCache);
void removeProjectParts(const QStringList &projectPartIds);

View File

@@ -27,6 +27,7 @@
#include "pchmanagerclient.h"
#include <filepathid.h>
#include <pchmanagerserverinterface.h>
#include <removepchprojectpartsmessage.h>
#include <updatepchprojectpartsmessage.h>
@@ -48,12 +49,14 @@ public:
sources.reserve(size);
}
Utils::PathStringVector headers;
Utils::PathStringVector sources;
ClangBackEnd::FilePathIds headers;
ClangBackEnd::FilePathIds sources;
};
ProjectUpdater::ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server)
: m_server(server)
ProjectUpdater::ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClangBackEnd::FilePathCachingInterface &filePathCache)
: m_server(server),
m_filePathCache(filePathCache)
{
}
@@ -83,14 +86,17 @@ void ProjectUpdater::setExcludedPaths(Utils::PathStringVector &&excludedPaths)
void ProjectUpdater::addToHeaderAndSources(HeaderAndSources &headerAndSources,
const CppTools::ProjectFile &projectFile) const
{
using ClangBackEnd::FilePathView;
Utils::PathString path = projectFile.path;
bool exclude = std::binary_search(m_excludedPaths.begin(), m_excludedPaths.end(), path);
if (!exclude) {
ClangBackEnd::FilePathId filePathId = m_filePathCache.filePathId(FilePathView(path));
if (projectFile.isSource())
headerAndSources.sources.push_back(path);
headerAndSources.sources.push_back(filePathId);
else if (projectFile.isHeader())
headerAndSources.headers.push_back(path);
headerAndSources.headers.push_back(filePathId);
}
}

View File

@@ -28,6 +28,7 @@
#include "clangpchmanager_global.h"
#include <filecontainerv2.h>
#include <filepathcachinginterface.h>
namespace CppTools {
class ProjectPart;
@@ -54,7 +55,8 @@ class PchManagerClient;
class CLANGPCHMANAGER_EXPORT ProjectUpdater
{
public:
ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server);
ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClangBackEnd::FilePathCachingInterface &filePathCache);
void updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts,
ClangBackEnd::V2::FileContainers &&generatedFiles);
@@ -77,6 +79,7 @@ unittest_public:
private:
Utils::PathStringVector m_excludedPaths;
ClangBackEnd::ProjectManagementServerInterface &m_server;
ClangBackEnd::FilePathCachingInterface &m_filePathCache;
};
} // namespace ClangPchManager

View File

@@ -55,14 +55,16 @@ class QtCreatorProjectUpdater : public ProjectUpdaterType
public:
template <typename ClientType>
QtCreatorProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClientType &client)
: ProjectUpdaterType(server, client)
ClientType &client,
ClangBackEnd::FilePathCachingInterface &filePathCache)
: ProjectUpdaterType(server, client, filePathCache)
{
connectToCppModelManager();
}
QtCreatorProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server)
: ProjectUpdaterType(server)
QtCreatorProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClangBackEnd::FilePathCachingInterface &filePathCache)
: ProjectUpdaterType(server, filePathCache)
{
connectToCppModelManager();
}

View File

@@ -88,7 +88,7 @@ public:
QtCreatorClangQueryFindFilter qtCreatorfindFilter{connectionClient.serverProxy(),
qtCreatorSearch,
refactoringClient};
ProjectUpdater projectUpdate{connectionClient.serverProxy()};
ProjectUpdater projectUpdate{connectionClient.serverProxy(), filePathCache};
};
ClangRefactoringPlugin::ClangRefactoringPlugin()

View File

@@ -28,8 +28,9 @@
namespace ClangRefactoring {
RefactoringProjectUpdater::RefactoringProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
RefactoringClient &)
: ClangPchManager::ProjectUpdater(server)
RefactoringClient &,
ClangBackEnd::FilePathCachingInterface &filePathCache)
: ClangPchManager::ProjectUpdater(server, filePathCache)
{
}

View File

@@ -35,7 +35,8 @@ class RefactoringProjectUpdater : public ClangPchManager::ProjectUpdater
{
public:
RefactoringProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
RefactoringClient &client);
RefactoringClient &client,
ClangBackEnd::FilePathCachingInterface &filePathCache);
};
} // namespace ClangRefactoring

View File

@@ -80,11 +80,18 @@ template <typename Source,
typename Target>
void append(Target &target, Source &source)
{
using ValueType = typename Target::value_type;
target.reserve(target.size() + source.size());
for (auto &&entry : source)
target.push_back(ValueType(entry));
target.emplace_back(entry);
}
void appendFilePathId(Utils::PathStringVector &target,
const ClangBackEnd::FilePathIds &source,
const ClangBackEnd::FilePathCachingInterface &filePathCache)
{
for (FilePathId id : source)
target.emplace_back(filePathCache.filePath(id).path());
}
template <typename GetterFunction>
@@ -110,7 +117,7 @@ void generateGlobal(Container &entries,
entries.reserve(entries.capacity() + globalCount(projectsParts, getterFunction));
for (const V2::ProjectPartContainer &projectPart : projectsParts) {
const auto &projectPartPaths = getterFunction(projectPart);
auto &&projectPartPaths = getterFunction(projectPart);
append(entries, projectPartPaths);
};
@@ -147,9 +154,8 @@ Utils::PathStringVector generatedFilePaths(const V2::FileContainers &generaredFi
Utils::PathStringVector PchCreator::generateGlobalHeaderPaths() const
{
auto includeFunction = [] (const V2::ProjectPartContainer &projectPart)
-> const Utils::PathStringVector & {
return projectPart.headerPaths();
auto includeFunction = [&] (const V2::ProjectPartContainer &projectPart) {
return m_filePathCache.filePaths(projectPart.headerPathIds());
};
Utils::PathStringVector headerPaths = generateGlobal<Utils::PathStringVector>(m_projectParts,
@@ -167,9 +173,8 @@ Utils::PathStringVector PchCreator::generateGlobalHeaderPaths() const
Utils::PathStringVector PchCreator::generateGlobalSourcePaths() const
{
auto sourceFunction = [] (const V2::ProjectPartContainer &projectPart)
-> const Utils::PathStringVector & {
return projectPart.sourcePaths();
auto sourceFunction = [&] (const V2::ProjectPartContainer &projectPart) {
return m_filePathCache.filePaths(projectPart.sourcePathIds());
};
return generateGlobal<Utils::PathStringVector>(m_projectParts, sourceFunction);
@@ -259,7 +264,7 @@ namespace {
std::size_t contentSize(const FilePaths &includes)
{
auto countIncludeSize = [] (std::size_t size, const Utils::PathString &include) {
auto countIncludeSize = [] (std::size_t size, const auto &include) {
return size + include.size();
};
@@ -275,7 +280,7 @@ Utils::SmallString PchCreator::generatePchIncludeFileContent(const FilePathIds &
fileContent.reserve(includes.size() * lineTemplateSize + contentSize(includes));
for (const Utils::PathString &include : includes)
for (const Utils::SmallStringView &include : includes)
fileContent += {"#include \"", include, "\"\n"};
return fileContent;
@@ -394,11 +399,14 @@ Utils::PathStringVector PchCreator::generateProjectPartHeaders(
const V2::ProjectPartContainer &projectPart) const
{
Utils::PathStringVector headerPaths;
headerPaths.reserve(projectPart.headerPaths().size() + m_generatedFiles.size());
headerPaths.reserve(projectPart.headerPathIds().size() + m_generatedFiles.size());
std::copy(projectPart.headerPaths().begin(),
projectPart.headerPaths().end(),
std::back_inserter(headerPaths));
std::transform(projectPart.headerPathIds().begin(),
projectPart.headerPathIds().end(),
std::back_inserter(headerPaths),
[&] (FilePathId filePathId) {
return m_filePathCache.filePath(filePathId);
});
Utils::PathStringVector generatedPath = generatedFilePaths(m_generatedFiles);
@@ -439,7 +447,7 @@ Utils::SmallString concatContent(const Utils::PathStringVector &paths, std::size
}
Utils::SmallString PchCreator::generateProjectPartHeaderAndSourcesContent(
const V2::ProjectPartContainer &projectPart)
const V2::ProjectPartContainer &projectPart) const
{
Utils::PathStringVector paths = generateProjectPartHeaderAndSourcePaths(projectPart);
@@ -447,13 +455,13 @@ Utils::SmallString PchCreator::generateProjectPartHeaderAndSourcesContent(
}
Utils::PathStringVector PchCreator::generateProjectPartHeaderAndSourcePaths(
const V2::ProjectPartContainer &projectPart)
const V2::ProjectPartContainer &projectPart) const
{
Utils::PathStringVector includeAndSources;
includeAndSources.reserve(projectPart.headerPaths().size() + projectPart.sourcePaths().size());
includeAndSources.reserve(projectPart.headerPathIds().size() + projectPart.sourcePathIds().size());
append(includeAndSources, projectPart.headerPaths());
append(includeAndSources, projectPart.sourcePaths());
appendFilePathId(includeAndSources, projectPart.headerPathIds(), m_filePathCache);
appendFilePathId(includeAndSources, projectPart.sourcePathIds(), m_filePathCache);
return includeAndSources;
}

View File

@@ -93,10 +93,10 @@ unittest_public:
const V2::ProjectPartContainer &projectPart) const;
Utils::PathStringVector generateProjectPartHeaders(
const V2::ProjectPartContainer &projectPart) const;
static Utils::SmallString generateProjectPartHeaderAndSourcesContent(
const V2::ProjectPartContainer &projectPart);
static Utils::PathStringVector generateProjectPartHeaderAndSourcePaths(
const V2::ProjectPartContainer &projectPart);
Utils::SmallString generateProjectPartHeaderAndSourcesContent(
const V2::ProjectPartContainer &projectPart) const;
Utils::PathStringVector generateProjectPartHeaderAndSourcePaths(
const V2::ProjectPartContainer &projectPart) const;
FilePathIds generateProjectPartPchIncludes(
const V2::ProjectPartContainer &projectPart) const;
Utils::SmallString generateProjectPathPchHeaderFilePath(

View File

@@ -12,7 +12,10 @@ HEADERS += \
$$PWD/storagesqlitestatementfactory.h \
$$PWD/symbolindexing.h \
$$PWD/symbolindexinginterface.h \
$$PWD/collectmacrospreprocessorcallbacks.h
$$PWD/collectmacrospreprocessorcallbacks.h \
$$PWD/projectpartentry.h \
$$PWD/useddefines.h \
$$PWD/symbolsvisitorbase.h
!isEmpty(LIBTOOLING_LIBS) {
SOURCES += \
@@ -58,4 +61,5 @@ HEADERS += \
SOURCES += \
$$PWD/sourcerangefilter.cpp \
$$PWD/symbolindexer.cpp \
$$PWD/symbolentry.cpp
$$PWD/symbolentry.cpp \
$$PWD/symbolstorageinterface.cpp

View File

@@ -58,6 +58,19 @@ void ClangTool::addFile(std::string &&directory,
m_sourceFilePaths.push_back(fileContent.filePath);
}
void ClangTool::addFiles(const FilePaths &filePaths, const Utils::SmallStringVector &arguments)
{
for (const FilePath &filePath : filePaths) {
std::vector<std::string> commandLine(arguments.begin(), arguments.end());
commandLine.push_back(std::string(filePath.name()));
addFile(filePath.directory(),
filePath.name(),
{},
std::move(commandLine));
}
}
template <typename Container>
void ClangTool::addFiles(const Container &filePaths,
const Utils::SmallStringVector &arguments)

View File

@@ -84,6 +84,9 @@ public:
template <typename Container>
void addFiles(const Container &filePaths,
const Utils::SmallStringVector &arguments);
void addFiles(const FilePaths &filePaths,
const Utils::SmallStringVector &arguments);
void addUnsavedFiles(const V2::FileContainers &unsavedFiles);

View File

@@ -25,7 +25,11 @@
#pragma once
#include "symbolsvisitorbase.h"
#include "sourcelocationsutils.h"
#include "sourcelocationentry.h"
#include "symbolentry.h"
#include "useddefines.h"
#include <filepath.h>
#include <filepathid.h>
@@ -36,14 +40,21 @@
namespace ClangBackEnd {
class CollectMacrosPreprocessorCallbacks final : public clang::PPCallbacks
class CollectMacrosPreprocessorCallbacks final : public clang::PPCallbacks,
public SymbolsVisitorBase
{
public:
CollectMacrosPreprocessorCallbacks(FilePathIds &sourceFiles,
FilePathCachingInterface &filePathCache)
: m_sourceFiles(sourceFiles),
m_filePathCache(filePathCache)
CollectMacrosPreprocessorCallbacks(SymbolEntries &symbolEntries,
SourceLocationEntries &sourceLocationEntries,
FilePathIds &sourceFiles,
UsedDefines &usedDefines,
FilePathCachingInterface &filePathCache,
const clang::SourceManager &sourceManager)
: SymbolsVisitorBase(filePathCache, sourceManager),
m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries),
m_sourceFiles(sourceFiles),
m_usedDefines(usedDefines)
{
}
@@ -70,6 +81,125 @@ public:
return true;
}
void Ifndef(clang::SourceLocation,
const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition) override
{
addUsedDefine(macroNameToken, macroDefinition);
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUsage);
}
void Ifdef(clang::SourceLocation,
const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition) override
{
addUsedDefine( macroNameToken, macroDefinition);
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUsage);
}
void Defined(const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition,
clang::SourceRange) override
{
addUsedDefine(macroNameToken, macroDefinition);
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUsage);
}
void MacroDefined(const clang::Token &macroNameToken,
const clang::MacroDirective *macroDirective) override
{
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDirective),
SymbolType::MacroDefinition);
}
void MacroUndefined(const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition,
const clang::MacroDirective *) override
{
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUndefinition);
}
void MacroExpands(const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition,
clang::SourceRange,
const clang::MacroArgs *) override
{
addUsedDefine(macroNameToken, macroDefinition);
addMacroAsSymbol(macroNameToken,
firstMacroInfo(macroDefinition.getLocalDirective()),
SymbolType::MacroUsage);
}
void addUsedDefine(const clang::Token &macroNameToken,
const clang::MacroDefinition &macroDefinition)
{
clang::MacroInfo *macroInfo = macroDefinition.getMacroInfo();
if (macroInfo) {
UsedDefine usedDefine{macroNameToken.getIdentifierInfo()->getName(),
filePathId(macroNameToken.getLocation())};
auto found = std::lower_bound(m_usedDefines.begin(),
m_usedDefines.end(), usedDefine);
if (found == m_usedDefines.end() || *found != usedDefine)
m_usedDefines.insert(found, std::move(usedDefine));
}
}
static const clang::MacroInfo *firstMacroInfo(const clang::MacroDirective *macroDirective)
{
if (macroDirective) {
const clang::MacroDirective *previousDirective = macroDirective;
do {
macroDirective = previousDirective;
previousDirective = macroDirective->getPrevious();
} while (previousDirective);
return macroDirective->getMacroInfo();
}
return nullptr;
}
void addMacroAsSymbol(const clang::Token &macroNameToken,
const clang::MacroInfo *macroInfo,
SymbolType symbolType)
{
clang::SourceLocation sourceLocation = macroNameToken.getLocation();
if (macroInfo && sourceLocation.isFileID()) {
FilePathId fileId = filePathId(sourceLocation);
auto macroName = macroNameToken.getIdentifierInfo()->getName();
if (fileId.isValid()) {
auto macroName = macroNameToken.getIdentifierInfo()->getName();
SymbolIndex globalId = toSymbolIndex(macroInfo);
auto found = m_symbolEntries.find(globalId);
if (found == m_symbolEntries.end()) {
Utils::optional<Utils::PathString> usr = generateUSR(macroName, sourceLocation);
if (usr) {
m_symbolEntries.emplace(std::piecewise_construct,
std::forward_as_tuple(globalId),
std::forward_as_tuple(std::move(usr.value()), macroName));
}
}
m_sourceLocationEntries.emplace_back(globalId,
fileId,
lineColum(sourceLocation),
symbolType);
}
}
}
void addSourceFile(const clang::FileEntry *file)
{
auto filePathId = m_filePathCache.filePathId(
@@ -82,8 +212,10 @@ public:
}
private:
SymbolEntries &m_symbolEntries;
SourceLocationEntries &m_sourceLocationEntries;
FilePathIds &m_sourceFiles;
FilePathCachingInterface &m_filePathCache;
UsedDefines &m_usedDefines;
bool m_skipInclude = false;
};

View File

@@ -33,8 +33,12 @@ namespace ClangBackEnd {
bool CollectMacrosSourceFileCallbacks::handleBeginSource(clang::CompilerInstance &compilerInstance)
{
auto callbacks = std::make_unique<CollectMacrosPreprocessorCallbacks>(m_sourceFiles,
m_filePathCache);
auto callbacks = std::make_unique<CollectMacrosPreprocessorCallbacks>(m_symbolEntries,
m_sourceLocationEntries,
m_sourceFiles,
m_usedDefines,
m_filePathCache,
compilerInstance.getSourceManager());
compilerInstance.getPreprocessorPtr()->addPPCallbacks(std::move(callbacks));

View File

@@ -25,6 +25,10 @@
#pragma once
#include "sourcelocationentry.h"
#include "symbolentry.h"
#include "useddefines.h"
#include <filepathcachinginterface.h>
#include <clang/Tooling/Tooling.h>
@@ -34,8 +38,12 @@ namespace ClangBackEnd {
class CollectMacrosSourceFileCallbacks : public clang::tooling::SourceFileCallbacks
{
public:
CollectMacrosSourceFileCallbacks(FilePathCachingInterface &filePathCache)
: m_filePathCache(filePathCache)
CollectMacrosSourceFileCallbacks(SymbolEntries &symbolEntries,
SourceLocationEntries &sourceLocationEntries,
FilePathCachingInterface &filePathCache)
: m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries),
m_filePathCache(filePathCache)
{
}
@@ -46,14 +54,9 @@ public:
return m_sourceFiles;
}
void addSourceFiles(const Utils::PathStringVector &filePaths)
void addSourceFiles(const FilePathIds &filePathIds)
{
std::transform(filePaths.begin(),
filePaths.end(),
std::back_inserter(m_sourceFiles),
[&] (const Utils::PathString &filePath) {
return m_filePathCache.filePathId(FilePathView{filePath});
});
m_sourceFiles = filePathIds;
}
void clearSourceFiles()
@@ -61,8 +64,16 @@ public:
m_sourceFiles.clear();
}
const UsedDefines &usedDefines() const
{
return m_usedDefines;
}
private:
FilePathIds m_sourceFiles;
UsedDefines m_usedDefines;
SymbolEntries &m_symbolEntries;
SourceLocationEntries &m_sourceLocationEntries;
FilePathCachingInterface &m_filePathCache;
};

View File

@@ -42,8 +42,12 @@ namespace ClangBackEnd {
class CollectSymbolsAction
{
public:
CollectSymbolsAction(FilePathCachingInterface &filePathCache)
: m_filePathCache(filePathCache)
CollectSymbolsAction(SymbolEntries &symbolEntries,
SourceLocationEntries &sourceLocationEntries,
FilePathCachingInterface &filePathCache)
: m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries),
m_filePathCache(filePathCache)
{}
std::unique_ptr<clang::ASTConsumer> newASTConsumer();
@@ -63,15 +67,9 @@ public:
return m_sourceLocationEntries;
}
void clear()
{
m_symbolEntries.clear();
m_sourceLocationEntries.clear();
}
private:
SymbolEntries m_symbolEntries;
SourceLocationEntries m_sourceLocationEntries;
SymbolEntries &m_symbolEntries;
SourceLocationEntries &m_sourceLocationEntries;
FilePathCachingInterface &m_filePathCache;
};

View File

@@ -25,32 +25,30 @@
#pragma once
#include "symbolentry.h"
#include "sourcelocationentry.h"
#include <filepathcachinginterface.h>
#include "sourcelocationsutils.h"
#include "symbolentry.h"
#include "symbolsvisitorbase.h"
#include <clang/AST/AST.h>
#include <clang/AST/ASTContext.h>
#include <clang/AST/RecursiveASTVisitor.h>
#include <clang/Index/USRGeneration.h>
#include <llvm/ADT/SmallVector.h>
#include <vector>
namespace ClangBackEnd {
class CollectSymbolsASTVisitor : public clang::RecursiveASTVisitor<CollectSymbolsASTVisitor>
class CollectSymbolsASTVisitor : public clang::RecursiveASTVisitor<CollectSymbolsASTVisitor>,
public SymbolsVisitorBase
{
public:
CollectSymbolsASTVisitor(SymbolEntries &symbolEntries,
SourceLocationEntries &sourceLocationEntries,
FilePathCachingInterface &filePathCache,
const clang::SourceManager &sourceManager)
: m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries),
m_filePathCache(filePathCache),
m_sourceManager(sourceManager)
: SymbolsVisitorBase(filePathCache, sourceManager),
m_symbolEntries(symbolEntries),
m_sourceLocationEntries(sourceLocationEntries)
{}
bool shouldVisitTemplateInstantiations() const
@@ -68,9 +66,12 @@ public:
auto found = m_symbolEntries.find(globalId);
if (found == m_symbolEntries.end()) {
Utils::optional<Utils::PathString> usr = generateUSR(declaration);
if (usr) {
m_symbolEntries.emplace(std::piecewise_construct,
std::forward_as_tuple(globalId),
std::forward_as_tuple(generateUSR(declaration), symbolName(declaration)));
std::forward_as_tuple(std::move(usr.value()), symbolName(declaration)));
}
}
m_sourceLocationEntries.emplace_back(globalId,
@@ -95,57 +96,15 @@ public:
return true;
}
FilePathId filePathId(clang::SourceLocation sourceLocation)
{
uint clangFileId = m_sourceManager.getFileID(sourceLocation).getHashValue();
auto found = m_filePathIndices.find(clangFileId);
if (found != m_filePathIndices.end())
return found->second;
auto filePath = m_sourceManager.getFilename(sourceLocation);
FilePathId filePathId = m_filePathCache.filePathId(FilePath::fromNativeFilePath(filePath));
m_filePathIndices.emplace(clangFileId, filePathId);
return filePathId;
}
LineColumn lineColum(clang::SourceLocation sourceLocation)
{
return {m_sourceManager.getSpellingLineNumber(sourceLocation),
m_sourceManager.getSpellingColumnNumber(sourceLocation)};
}
Utils::PathString generateUSR(const clang::Decl *declaration)
{
llvm::SmallVector<char, 128> usr;
clang::index::generateUSRForDecl(declaration, usr);
return {usr.data(), usr.size()};
}
Utils::SmallString symbolName(const clang::NamedDecl *declaration)
{
const llvm::StringRef symbolName{declaration->getName()};
return {symbolName.data(), symbolName.size()};
}
static SymbolIndex toSymbolIndex(const void *pointer)
{
return SymbolIndex(reinterpret_cast<std::uintptr_t>(pointer));
return declaration->getName();
}
private:
SymbolEntries &m_symbolEntries;
std::unordered_map<uint, FilePathId> m_filePathIndices;
SourceLocationEntries &m_sourceLocationEntries;
FilePathCachingInterface &m_filePathCache;
const clang::SourceManager &m_sourceManager;
};

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <filepathid.h>
#include <utils/smallstringvector.h>
namespace ClangBackEnd {
class ProjectPartEntry
{
public:
ProjectPartEntry(Utils::SmallStringView projectPathName,
const FilePathIds &filePathIds,
Utils::SmallStringVector &&compilerArguments)
: projectPathName(projectPathName), filePathIds(filePathIds), compilerArguments(compilerArguments)
{}
friend bool operator==(const ProjectPartEntry &first, const ProjectPartEntry &second)
{
return first.projectPathName == second.projectPathName
&& first.filePathIds == second.filePathIds
&& first.compilerArguments == second.compilerArguments;
}
public:
Utils::PathString projectPathName;
FilePathIds filePathIds;
Utils::SmallStringVector compilerArguments;
};
using ProjectPartEntries = std::vector<ProjectPartEntry>;
} // namespace ClangBackEnd

View File

@@ -27,6 +27,8 @@
#include <filepathid.h>
#include <utils/linecolumn.h>
#include <limits>
#include <vector>
@@ -37,19 +39,10 @@ namespace ClangBackEnd {
enum class SymbolType
{
Declaration,
DeclarationReference
};
class LineColumn
{
public:
LineColumn(uint line, uint column)
: line(line),
column(column)
{}
uint line = 0;
uint column = 0;
DeclarationReference,
MacroDefinition,
MacroUsage,
MacroUndefinition
};
using SymbolIndex = long long;
@@ -59,27 +52,24 @@ class SourceLocationEntry
public:
SourceLocationEntry(SymbolIndex symbolId,
FilePathId filePathId,
LineColumn lineColumn,
Utils::LineColumn lineColumn,
SymbolType symbolType)
: symbolId(symbolId),
filePathId(filePathId),
line(lineColumn.line),
column(lineColumn.column),
lineColumn(lineColumn),
symbolType(symbolType)
{}
SymbolIndex symbolId = 0;
FilePathId filePathId;
uint line = 0;
uint column = 0;
Utils::LineColumn lineColumn;
SymbolType symbolType;
friend bool operator==(const SourceLocationEntry &first, const SourceLocationEntry &second)
{
return first.symbolId == second.symbolId
&& first.filePathId == second.filePathId
&& first.line == second.line
&& first.column == second.column
&& first.lineColumn == second.lineColumn
&& first.symbolType == second.symbolType;
}
};

View File

@@ -57,7 +57,7 @@ public:
table.addIndex({usrColumn, symbolNameColumn});
table.addIndex({symbolIdColumn});
Sqlite::ImmediateTransaction<DatabaseType> transaction(database);
Sqlite::ImmediateTransaction transaction(database);
table.initialize(database);
transaction.commit();
@@ -76,7 +76,7 @@ public:
const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer);
table.addIndex({sourceIdColumn});
Sqlite::ImmediateTransaction<DatabaseType> transaction(database);
Sqlite::ImmediateTransaction transaction(database);
table.initialize(database);
transaction.commit();
@@ -128,6 +128,30 @@ public:
"DELETE FROM newLocations",
database
};
WriteStatement insertProjectPart{
"INSERT OR IGNORE INTO projectParts(projectPartName, compilerArguments) VALUES (?,?)",
database
};
WriteStatement updateProjectPart{
"UPDATE projectParts SET compilerArguments = ? WHERE projectPartName = ?",
database
};
ReadStatement getProjectPartId{
"SELECT projectPartId FROM projectParts WHERE projectPartName = ?",
database
};
WriteStatement deleteAllProjectPartsSourcesWithProjectPartId{
"DELETE FROM projectPartsSources WHERE projectPartId = ?",
database
};
WriteStatement insertProjectPartSources{
"INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?)",
database
};
ReadStatement getCompileArgumentsForFileId{
"SELECT compilerArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?)",
database
};
};
} // namespace ClangBackEnd

View File

@@ -29,28 +29,47 @@ namespace ClangBackEnd {
SymbolIndexer::SymbolIndexer(SymbolsCollectorInterface &symbolsCollector,
SymbolStorageInterface &symbolStorage,
ClangPathWatcherInterface &pathWatcher)
ClangPathWatcherInterface &pathWatcher,
FilePathCachingInterface &filePathCache,
Sqlite::TransactionInterface &transactionInterface)
: m_symbolsCollector(symbolsCollector),
m_symbolStorage(symbolStorage),
m_pathWatcher(pathWatcher)
m_pathWatcher(pathWatcher),
m_filePathCache(filePathCache),
m_transactionInterface(transactionInterface)
{
pathWatcher.setNotifier(this);
}
void SymbolIndexer::updateProjectParts(V2::ProjectPartContainers &&projectParts,
V2::FileContainers &&generatedFiles)
void SymbolIndexer::updateProjectParts(V2::ProjectPartContainers &&projectParts, V2::FileContainers &&generatedFiles)
{
for (V2::ProjectPartContainer &projectPart : projectParts)
updateProjectPart(std::move(projectPart), generatedFiles);
}
void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart,
const V2::FileContainers &generatedFiles)
{
m_symbolsCollector.clear();
for (const V2::ProjectPartContainer &projectPart : projectParts)
m_symbolsCollector.addFiles(projectPart.sourcePaths(), projectPart.arguments());
m_symbolsCollector.addFiles(projectPart.sourcePathIds(), projectPart.arguments());
m_symbolsCollector.addUnsavedFiles(generatedFiles);
m_symbolsCollector.collectSymbols();
Sqlite::ImmediateTransaction transaction{m_transactionInterface};
m_symbolStorage.addSymbolsAndSourceLocations(m_symbolsCollector.symbols(),
m_symbolsCollector.sourceLocations());
m_symbolStorage.insertOrUpdateProjectPart(projectPart.projectPartId(),
projectPart.arguments());
m_symbolStorage.updateProjectPartSources(projectPart.projectPartId(),
m_symbolsCollector.sourceFiles());
transaction.commit();
}
void SymbolIndexer::pathsWithIdsChanged(const Utils::SmallStringVector &)

View File

@@ -39,10 +39,14 @@ class SymbolIndexer : public ClangPathWatcherNotifier
public:
SymbolIndexer(SymbolsCollectorInterface &symbolsCollector,
SymbolStorageInterface &symbolStorage,
ClangPathWatcherInterface &pathWatcher);
ClangPathWatcherInterface &pathWatcher,
FilePathCachingInterface &filePathCache,
Sqlite::TransactionInterface &transactionInterface);
void updateProjectParts(V2::ProjectPartContainers &&projectParts,
V2::FileContainers &&generatedFiles);
void updateProjectPart(V2::ProjectPartContainer &&projectPart,
const V2::FileContainers &generatedFiles);
void pathsWithIdsChanged(const Utils::SmallStringVector &ids) override;
void pathsChanged(const FilePathIds &filePathIds) override;
@@ -51,6 +55,8 @@ private:
SymbolsCollectorInterface &m_symbolsCollector;
SymbolStorageInterface &m_symbolStorage;
ClangPathWatcherInterface &m_pathWatcher;
FilePathCachingInterface &m_filePathCache;
Sqlite::TransactionInterface &m_transactionInterface;
};
} // namespace ClangBackEnd

View File

@@ -75,7 +75,7 @@ private:
StatementFactory m_statementFactory;
Storage m_symbolStorage{m_statementFactory, m_filePathCache};
ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache};
SymbolIndexer m_indexer{m_collector, m_symbolStorage, m_sourceWatcher};
SymbolIndexer m_indexer{m_collector, m_symbolStorage, m_sourceWatcher, m_filePathCache, m_statementFactory.database};
};
} // namespace ClangBackEnd

View File

@@ -28,15 +28,17 @@
namespace ClangBackEnd {
SymbolsCollector::SymbolsCollector(FilePathCachingInterface &filePathCache)
: m_collectSymbolsAction(filePathCache),
m_collectMacrosSourceFileCallbacks(filePathCache)
: m_collectSymbolsAction(m_symbolEntries, m_sourceLocationEntries, filePathCache),
m_collectMacrosSourceFileCallbacks(m_symbolEntries, m_sourceLocationEntries, filePathCache),
m_filePathCache(filePathCache)
{
}
void SymbolsCollector::addFiles(const Utils::PathStringVector &filePaths, const Utils::SmallStringVector &arguments)
void SymbolsCollector::addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments)
{
m_clangTool.addFiles(filePaths, arguments);
m_collectMacrosSourceFileCallbacks.addSourceFiles(filePaths);
m_clangTool.addFiles(m_filePathCache.filePaths(filePathIds), arguments);
m_collectMacrosSourceFileCallbacks.addSourceFiles(filePathIds);
}
void SymbolsCollector::addUnsavedFiles(const V2::FileContainers &unsavedFiles)
@@ -47,8 +49,8 @@ void SymbolsCollector::addUnsavedFiles(const V2::FileContainers &unsavedFiles)
void SymbolsCollector::clear()
{
m_collectMacrosSourceFileCallbacks.clearSourceFiles();
m_collectSymbolsAction.clear();
m_symbolEntries.clear();
m_sourceLocationEntries.clear();
m_clangTool = ClangTool();
}
@@ -75,4 +77,9 @@ const FilePathIds &SymbolsCollector::sourceFiles() const
return m_collectMacrosSourceFileCallbacks.sourceFiles();
}
const UsedDefines &SymbolsCollector::usedDefines() const
{
return m_collectMacrosSourceFileCallbacks.usedDefines();
}
} // namespace ClangBackEnd

View File

@@ -29,7 +29,6 @@
#include "collectmacrossourcefilecallbacks.h"
#include "collectsymbolsaction.h"
#include "symbolscollectorinterface.h"
#include "symbolentry.h"
#include <filepathcachingfwd.h>
@@ -40,7 +39,7 @@ class SymbolsCollector : public SymbolsCollectorInterface
public:
SymbolsCollector(FilePathCachingInterface &filePathCache);
void addFiles(const Utils::PathStringVector &filePaths,
void addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments) override;
void addUnsavedFiles(const V2::FileContainers &unsavedFiles) override;
@@ -52,11 +51,15 @@ public:
const SymbolEntries &symbols() const override;
const SourceLocationEntries &sourceLocations() const override;
const FilePathIds &sourceFiles() const override;
const UsedDefines &usedDefines() const override;
private:
ClangTool m_clangTool;
SymbolEntries m_symbolEntries;
SourceLocationEntries m_sourceLocationEntries;
CollectSymbolsAction m_collectSymbolsAction;
CollectMacrosSourceFileCallbacks m_collectMacrosSourceFileCallbacks;
FilePathCachingInterface &m_filePathCache;
};
} // namespace ClangBackEnd

View File

@@ -27,6 +27,7 @@
#include "symbolentry.h"
#include "sourcelocationentry.h"
#include "useddefines.h"
#include <filecontainerv2.h>
@@ -40,7 +41,7 @@ namespace ClangBackEnd {
class SymbolsCollectorInterface
{
public:
virtual void addFiles(const Utils::PathStringVector &filePaths,
virtual void addFiles(const FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments) = 0;
virtual void addUnsavedFiles(const V2::FileContainers &unsavedFiles) = 0;
@@ -52,6 +53,7 @@ public:
virtual const SymbolEntries &symbols() const = 0;
virtual const SourceLocationEntries &sourceLocations() const = 0;
virtual const FilePathIds &sourceFiles() const = 0;
virtual const UsedDefines &usedDefines() const = 0;
};
} // namespace ClangBackEnd

View File

@@ -31,12 +31,14 @@
#include <sqlitetransaction.h>
#include <filepathcachingfwd.h>
#include <QJsonDocument>
#include <QJsonArray>
namespace ClangBackEnd {
template <typename StatementFactory>
class SymbolStorage : public SymbolStorageInterface
class SymbolStorage final : public SymbolStorageInterface
{
using Transaction = Sqlite::ImmediateTransaction<typename StatementFactory::DatabaseType>;
using ReadStatement = typename StatementFactory::ReadStatementType;
using WriteStatement = typename StatementFactory::WriteStatementType;
using Database = typename StatementFactory::DatabaseType;
@@ -52,8 +54,6 @@ public:
void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries,
const SourceLocationEntries &sourceLocations) override
{
Transaction transaction{m_statementFactory.database};
fillTemporarySymbolsTable(symbolEntries);
fillTemporaryLocationsTable(sourceLocations);
addNewSymbolsToSymbols();
@@ -63,8 +63,50 @@ public:
insertNewLocationsInLocations();
deleteNewSymbolsTable();
deleteNewLocationsTable();
}
transaction.commit();
void insertOrUpdateProjectPart(Utils::SmallStringView projectPartName,
const Utils::SmallStringVector &commandLineArguments) override
{
m_statementFactory.database.setLastInsertedRowId(-1);
Utils::SmallString compilerArguementsAsJson = toJson(commandLineArguments);
WriteStatement &insertStatement = m_statementFactory.insertProjectPart;
insertStatement.write(projectPartName, compilerArguementsAsJson);
if (m_statementFactory.database.lastInsertedRowId() == -1) {
WriteStatement &updateStatement = m_statementFactory.updateProjectPart;
updateStatement.write(compilerArguementsAsJson, projectPartName);
}
}
void updateProjectPartSources(Utils::SmallStringView projectPartName,
const FilePathIds &sourceFilePathIds) override
{
ReadStatement &getProjectPartIdStatement = m_statementFactory.getProjectPartId;
int projectPartId = getProjectPartIdStatement.template value<int>(projectPartName).value();
WriteStatement &deleteStatement = m_statementFactory.deleteAllProjectPartsSourcesWithProjectPartId;
deleteStatement.write(projectPartId);
WriteStatement &insertStatement = m_statementFactory.insertProjectPartSources;
for (const FilePathId &sourceFilePathId : sourceFilePathIds)
insertStatement.write(projectPartId, sourceFilePathId.filePathId);
}
static Utils::SmallString toJson(const Utils::SmallStringVector &strings)
{
QJsonDocument document;
QJsonArray array;
std::transform(strings.begin(), strings.end(), std::back_inserter(array), [] (const auto &string) {
return QJsonValue(string.data());
});
document.setArray(array);
return document.toJson(QJsonDocument::Compact);
}
void fillTemporarySymbolsTable(const SymbolEntries &symbolEntries)
@@ -84,8 +126,8 @@ public:
for (const auto &locationsEntry : sourceLocations) {
statement.write(locationsEntry.symbolId,
locationsEntry.line,
locationsEntry.column,
locationsEntry.lineColumn.line,
locationsEntry.lineColumn.column,
locationsEntry.filePathId.filePathId);
}
}

View File

@@ -0,0 +1,34 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "symbolstorageinterface.h"
namespace ClangBackEnd {
SymbolStorageInterface::~SymbolStorageInterface()
{
}
}

View File

@@ -25,16 +25,28 @@
#pragma once
#include "projectpartentry.h"
#include "sourcelocationentry.h"
#include "symbolentry.h"
#include <sqlitetransaction.h>
namespace ClangBackEnd {
class SymbolStorageInterface
{
public:
SymbolStorageInterface() = default;
virtual ~SymbolStorageInterface();
SymbolStorageInterface(const SymbolStorageInterface &) = delete;
SymbolStorageInterface &operator=(const SymbolStorageInterface &) = delete;
virtual void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries,
const SourceLocationEntries &sourceLocations) = 0;
virtual void insertOrUpdateProjectPart(Utils::SmallStringView projectPartName,
const Utils::SmallStringVector &commandLineArguments) = 0;
virtual void updateProjectPartSources(Utils::SmallStringView projectPartName,
const FilePathIds &sourceFilePathIds) = 0;
};
} // namespace ClangBackEnd

View File

@@ -0,0 +1,121 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "sourcelocationsutils.h"
#include <filepathcachinginterface.h>
#include <utils/linecolumn.h>
#include <utils/optional.h>
#include <clang/Basic/SourceLocation.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Index/USRGeneration.h>
#include <llvm/ADT/SmallVector.h>
namespace ClangBackEnd {
class SymbolsVisitorBase
{
public:
SymbolsVisitorBase(FilePathCachingInterface &filePathCache,
const clang::SourceManager &sourceManager)
: m_filePathCache(filePathCache),
m_sourceManager(sourceManager)
{}
FilePathId filePathId(clang::SourceLocation sourceLocation)
{
uint clangFileId = m_sourceManager.getFileID(sourceLocation).getHashValue();
auto found = m_filePathIndices.find(clangFileId);
if (found != m_filePathIndices.end())
return found->second;
auto filePath = m_sourceManager.getFilename(sourceLocation);
if (filePath.size() > 0) {
FilePathId filePathId = m_filePathCache.filePathId(FilePath::fromNativeFilePath(absolutePath(filePath)));
m_filePathIndices.emplace(clangFileId, filePathId);
return filePathId;
}
return {};
}
Utils::LineColumn lineColum(clang::SourceLocation sourceLocation)
{
return {int(m_sourceManager.getSpellingLineNumber(sourceLocation)),
int(m_sourceManager.getSpellingColumnNumber(sourceLocation))};
}
static Utils::optional<Utils::PathString> generateUSR(const clang::Decl *declaration)
{
llvm::SmallVector<char, 128> usr;
Utils::optional<Utils::PathString> usrOptional;
bool wasNotWorking = clang::index::generateUSRForDecl(declaration, usr);
if (!wasNotWorking)
usrOptional.emplace(usr.data(), usr.size());
return usrOptional;
}
Utils::optional<Utils::PathString> generateUSR(clang::StringRef macroName,
clang::SourceLocation sourceLocation)
{
llvm::SmallVector<char, 128> usr;
Utils::optional<Utils::PathString> usrOptional;
bool wasNotWorking = clang::index::generateUSRForMacro(macroName,
sourceLocation,
m_sourceManager,
usr);
if (!wasNotWorking)
usrOptional.emplace(usr.data(), usr.size());
return usrOptional;
}
static SymbolIndex toSymbolIndex(const void *pointer)
{
return SymbolIndex(reinterpret_cast<std::uintptr_t>(pointer));
}
protected:
std::unordered_map<uint, FilePathId> m_filePathIndices;
FilePathCachingInterface &m_filePathCache;
const clang::SourceManager &m_sourceManager;
};
} // namespace ClangBackend

View File

@@ -0,0 +1,66 @@
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <filepathid.h>
#include <utils/smallstring.h>
#include <vector>
namespace ClangBackEnd {
class UsedDefine
{
public:
UsedDefine(Utils::SmallStringView defineName, FilePathId filePathId)
: defineName(defineName),
filePathId(filePathId)
{}
friend bool operator<(const UsedDefine &first, const UsedDefine &second)
{
return std::tie(first.filePathId, first.defineName)
< std::tie(second.filePathId, second.defineName);
}
friend bool operator==(const UsedDefine &first, const UsedDefine &second)
{
return first.filePathId == second.filePathId && first.defineName == second.defineName;
}
friend bool operator!=(const UsedDefine &first, const UsedDefine &second)
{
return !(first == second);
}
public:
Utils::SmallString defineName;
FilePathId filePathId;
};
using UsedDefines = std::vector<UsedDefine>;
} // ClangBackEnd

View File

@@ -0,0 +1,36 @@
#ifndef SYMBOLSCOLLECTOR_DEFINES_H
#define SYMBOLSCOLLECTOR_DEFINES_H
#define IF_NOT_DEFINE 1
#ifndef IF_NOT_DEFINE
#endif
#ifndef IF_NOT_DEFINE
#endif
#ifndef COMPILER_ARGUMENT
#endif
#define IF_DEFINE 1
#ifdef IF_DEFINE
#endif
#define DEFINED 1
#if defined(DEFINED)
#endif
#define MACRO_EXPANSION int
void foo(MACRO_EXPANSION);
#ifndef __clang__
#endif
#define UN_DEFINE
#undef UN_DEFINE
#endif // SYMBOLSCOLLECTOR_DEFINES_H

View File

@@ -48,8 +48,7 @@ protected:
void SetUp();
protected:
NiceMock<MockMutex> mockMutex;
NiceMock<MockSqliteDatabase> mockDatabase{mockMutex};
NiceMock<MockSqliteDatabase> mockDatabase;
StatementFactory factory{mockDatabase};
MockSqliteReadStatement &selectDirectoryIdFromDirectoriesByDirectoryPath = factory.selectDirectoryIdFromDirectoriesByDirectoryPath;
MockSqliteReadStatement &selectSourceIdFromSourcesByDirectoryIdAndSourceName = factory.selectSourceIdFromSourcesByDirectoryIdAndSourceName;
@@ -134,14 +133,14 @@ TEST_F(FilePathStorage, FetchSourceIdForPathAndDirectoryId)
TEST_F(FilePathStorage, CallWriteForWriteDirectory)
{
EXPECT_CALL(insertIntoDirectories, write(Eq("/some/not/known/path")));
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/some/not/known/path")));
storage.writeDirectoryId("/some/not/known/path");
}
TEST_F(FilePathStorage, CallWriteForWriteSource)
{
EXPECT_CALL(insertIntoSources, write(5, Eq("unknownfile.h")));
EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("unknownfile.h")));
storage.writeSourceId(5, "unknownfile.h");
}
@@ -178,10 +177,10 @@ TEST_F(FilePathStorage, CallSelectForFetchingDirectoryIdForKnownPath)
{
InSequence s;
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
valueReturnInt32(Eq("/path/to")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchDirectoryId("/path/to");
}
@@ -190,24 +189,24 @@ TEST_F(FilePathStorage, CallSelectForFetchingSourceIdForKnownPath)
{
InSequence s;
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName,
valueReturnInt32(5, Eq("file.h")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchSourceId(5, "file.h");
}
TEST_F(FilePathStorage, CallNotWriteForFetchingDirectoryIdForKnownPath)
{
EXPECT_CALL(insertIntoDirectories, write(_)).Times(0);
EXPECT_CALL(insertIntoDirectories, write(An<Utils::SmallStringView>())).Times(0);
storage.fetchDirectoryId("/path/to");
}
TEST_F(FilePathStorage, CallNotWriteForFetchingSoureIdForKnownEntry)
{
EXPECT_CALL(insertIntoSources, write(_, _)).Times(0);
EXPECT_CALL(insertIntoSources, write(An<uint>(), An<Utils::SmallStringView>())).Times(0);
storage.fetchSourceId(5, "file.h");
}
@@ -216,11 +215,11 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdForUnknownPath)
{
InSequence s;
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
valueReturnInt32(Eq("/some/not/known/path")));
EXPECT_CALL(insertIntoDirectories, write(Eq("/some/not/known/path")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/some/not/known/path")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchDirectoryId("/some/not/known/path");
}
@@ -229,11 +228,11 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceIdForUnknownEntry)
{
InSequence s;
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName,
valueReturnInt32(5, Eq("unknownfile.h")));
EXPECT_CALL(insertIntoSources, write(5, Eq("unknownfile.h")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("unknownfile.h")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchSourceId(5, "unknownfile.h");
}
@@ -242,17 +241,17 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdTwoTimesIfTheDat
{
InSequence s;
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
valueReturnInt32(Eq("/other/unknow/path")));
EXPECT_CALL(insertIntoDirectories, write(Eq("/other/unknow/path")))
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path")))
.WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
EXPECT_CALL(mockDatabase, execute(Eq("ROLLBACK")));
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase, rollback());
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
valueReturnInt32(Eq("/other/unknow/path")));
EXPECT_CALL(insertIntoDirectories, write(Eq("/other/unknow/path")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchDirectoryId("/other/unknow/path");
}
@@ -262,17 +261,17 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheDatabase
{
InSequence s;
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName,
valueReturnInt32(5, Eq("otherunknownfile.h")));
EXPECT_CALL(insertIntoSources, write(5, Eq("otherunknownfile.h")))
EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("otherunknownfile.h")))
.WillOnce(Throw(Sqlite::StatementIsBusy("busy")));;
EXPECT_CALL(mockDatabase, execute(Eq("ROLLBACK")));
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase, rollback());
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName,
valueReturnInt32(5, Eq("otherunknownfile.h")));
EXPECT_CALL(insertIntoSources, write(5, Eq("otherunknownfile.h")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(insertIntoSources, write(5, TypedEq<Utils::SmallStringView>("otherunknownfile.h")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchSourceId(5, "otherunknownfile.h");
}
@@ -295,27 +294,27 @@ TEST_F(FilePathStorage, SelectAllSources)
TEST_F(FilePathStorage, CallSelectAllDirectories)
{
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectAllDirectories, valuesReturnStdVectorDirectory(256));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchAllDirectories();
}
TEST_F(FilePathStorage, CallSelectAllSources)
{
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectAllSources, valuesReturnStdVectorSource(8192));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchAllSources();
}
TEST_F(FilePathStorage, CallValueForFetchDirectoryPathForId)
{
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectDirectoryPathFromDirectoriesByDirectoryId, valueReturnPathString(5));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchDirectoryPath(5);
}
@@ -334,9 +333,9 @@ TEST_F(FilePathStorage, ThrowAsFetchingDirectoryPathForNonExistingId)
TEST_F(FilePathStorage, CallValueForFetchSoureNameForId)
{
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectSourceNameFromSourcesBySourceId, valueReturnSmallString(42));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchSourceName(42);
}
@@ -388,14 +387,13 @@ void FilePathStorage::SetUp()
valueReturnSmallString(42))
.WillByDefault(Return(Utils::optional<Utils::SmallString>("file.cpp")));
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(_))
.Times(AnyNumber());
EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(_, _))
.Times(AnyNumber());
EXPECT_CALL(insertIntoDirectories,write(_))
EXPECT_CALL(insertIntoDirectories, write(An<Utils::SmallStringView>()))
.Times(AnyNumber());
EXPECT_CALL(insertIntoSources,write(_, _))
EXPECT_CALL(insertIntoSources, write(An<uint>(), _))
.Times(AnyNumber());
EXPECT_CALL(selectAllDirectories, valuesReturnStdVectorDirectory(_))
.Times(AnyNumber());

View File

@@ -41,8 +41,7 @@ using StatementFactory = ClangBackEnd::FilePathStorageSqliteStatementFactory<Nic
class FilePathStorageSqliteStatementFactory : public testing::Test
{
protected:
NiceMock<MockMutex> mockMutex;
NiceMock<MockSqliteDatabase> mockDatabase{mockMutex};
NiceMock<MockSqliteDatabase> mockDatabase;
StatementFactory factory{mockDatabase};
};

View File

@@ -28,7 +28,9 @@
#include <gmock/gmock.h>
using testing::_;
using testing::A;
using testing::AllOf;
using testing::An;
using testing::AnyNumber;
using testing::AnyOf;
using testing::Assign;
@@ -38,6 +40,7 @@ using testing::Field;
using testing::HasSubstr;
using testing::InSequence;
using testing::IsEmpty;
using testing::Matcher;
using testing::Mock;
using testing::MockFunction;
using testing::NiceMock;
@@ -47,10 +50,12 @@ using testing::PrintToString;
using testing::Property;
using testing::Return;
using testing::ReturnRef;
using testing::SafeMatcherCast;
using testing::Sequence;
using testing::SizeIs;
using testing::StrEq;
using testing::Throw;
using testing::TypedEq;
using testing::UnorderedElementsAre;
using testing::Eq;

View File

@@ -43,6 +43,8 @@
#include <tokeninfos.h>
#include <filepathview.h>
#include <tooltipinfo.h>
#include <projectpartentry.h>
#include <useddefines.h>
#include <cpptools/usages.h>
@@ -114,6 +116,12 @@ std::ostream &operator<<(std::ostream &out, const Macro &macro)
} // namespace ProjectExplorer
namespace Utils {
std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn)
{
return out << "(" << lineColumn.line << ", " << lineColumn.column << ")";
}
void PrintTo(const Utils::SmallString &text, ::std::ostream *os)
{
*os << text;
@@ -152,12 +160,27 @@ std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths)
return out;
}
#define RETURN_TEXT_FOR_CASE(enumValue) case SymbolType::enumValue: return #enumValue
static const char *symbolTypeToCStringLiteral(SymbolType type)
{
switch (type) {
RETURN_TEXT_FOR_CASE(Declaration);
RETURN_TEXT_FOR_CASE(DeclarationReference);
RETURN_TEXT_FOR_CASE(MacroDefinition);
RETURN_TEXT_FOR_CASE(MacroUsage);
}
return "";
}
#undef RETURN_TEXT_FOR_CASE
std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry)
{
out << "("
<< entry.symbolId << ", "
<< entry.filePathId << ", "
<< entry.line << ", "
<< entry.column << ")";
<< entry.lineColumn << ", "
<< symbolTypeToCStringLiteral(entry.symbolType) << ")";
return out;
}
@@ -785,6 +808,24 @@ std::ostream &operator<<(std::ostream &out, const FilePath &filePath)
return out << "(" << filePath.path() << ", " << filePath.slashIndex() << ")";
}
std::ostream &operator<<(std::ostream &out, const ProjectPartEntry &projectPartEntry)
{
return out << "("
<< projectPartEntry.projectPathName
<< ", "
<< projectPartEntry.filePathIds
<< ")";
}
std::ostream &operator<<(std::ostream &out, const UsedDefine &usedDefine)
{
return out << "("
<< usedDefine.filePathId
<< ", "
<< usedDefine.defineName
<< ")";
}
void PrintTo(const FilePath &filePath, ::std::ostream *os)
{
*os << filePath;
@@ -795,6 +836,11 @@ void PrintTo(const FilePathView &filePathView, ::std::ostream *os)
*os << filePathView;
}
void PrintTo(const FilePathId &filePathId, ::std::ostream *os)
{
*os << filePathId;
}
namespace V2 {
std::ostream &operator<<(std::ostream &os, const FileContainer &container)
@@ -818,8 +864,8 @@ std::ostream &operator<<(std::ostream &out, const ProjectPartContainer &containe
out << "("
<< container.projectPartId() << ", "
<< container.arguments() << ", "
<< container.headerPaths() << ", "
<< container.sourcePaths()<< ")";
<< container.headerPathIds() << ", "
<< container.sourcePathIds()<< ")";
return out;
}

View File

@@ -61,6 +61,10 @@ std::ostream &operator<<(std::ostream &out, const Macro &macro);
} // namespace ClangRefactoring
namespace Utils {
class LineColumn;
std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn);
void PrintTo(const Utils::SmallString &text, ::std::ostream *os);
void PrintTo(const Utils::PathString &text, ::std::ostream *os);
} // namespace ProjectExplorer
@@ -127,6 +131,8 @@ class AbstractFilePathView;
using FilePathView = AbstractFilePathView<'/'>;
using NativeFilePathView = AbstractFilePathView<'\\'>;
class ToolTipInfo;
class ProjectPartEntry;
class UsedDefine;
std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry);
std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths);
@@ -188,9 +194,12 @@ std::ostream &operator<<(std::ostream &out, const TokenInfo& tokenInfo);
std::ostream &operator<<(std::ostream &out, const TokenInfos &tokenInfos);
std::ostream &operator<<(std::ostream &out, const FilePathView &filePathView);
std::ostream &operator<<(std::ostream &out, const NativeFilePathView &nativeFilePathView);
std::ostream &operator<<(std::ostream &out, const ProjectPartEntry &projectPartEntry);
std::ostream &operator<<(std::ostream &out, const UsedDefine &usedDefine);
void PrintTo(const FilePath &filePath, ::std::ostream *os);
void PrintTo(const FilePathView &filePathView, ::std::ostream *os);
void PrintTo(const FilePathId &filePathId, ::std::ostream *os);
namespace V2 {
class FileContainer;

View File

@@ -27,31 +27,23 @@
#include "googletest.h"
#include "mockmutex.h"
#include "mocksqlitetransactionbackend.h"
#include <sqlitetable.h>
#include <sqlitetransaction.h>
#include <utils/smallstringview.h>
class MockSqliteDatabase
class MockSqliteDatabase : public MockSqliteTransactionBackend
{
public:
using MutexType = MockMutex;
MockSqliteDatabase() = default;
MockSqliteDatabase(const MockMutex &mockMutex)
{
ON_CALL(*this, databaseMutex())
.WillByDefault(ReturnRef(const_cast<MockMutex &>(mockMutex)));
}
MOCK_METHOD1(execute,
void (Utils::SmallStringView sqlStatement));
MOCK_METHOD0(databaseMutex,
MockMutex &());
MOCK_CONST_METHOD0(lastInsertedRowId,
int64_t ());
MOCK_CONST_METHOD1(setLastInsertedRowId,
void (int64_t));
};

View File

@@ -65,6 +65,13 @@ MockSqliteReadStatement::value<int>(const Utils::SmallStringView &text)
return valueReturnInt32(text);
}
template <>
Utils::optional<int>
MockSqliteReadStatement::value<int>(const Utils::PathString &text)
{
return valueReturnInt32(text);
}
template <>
Utils::optional<int>
MockSqliteReadStatement::value<int>(const int &directoryId, const Utils::SmallStringView &text)

View File

@@ -129,6 +129,10 @@ template <>
Utils::optional<int>
MockSqliteReadStatement::value<int>(const Utils::SmallStringView&);
template <>
Utils::optional<int>
MockSqliteReadStatement::value<int>(const Utils::PathString&);
template <>
Utils::optional<int>
MockSqliteReadStatement::value<int>(const int&, const Utils::SmallStringView&);
@@ -137,6 +141,8 @@ template <>
Utils::optional<Utils::PathString>
MockSqliteReadStatement::value<Utils::PathString>(const int&);
template <>
Utils::optional<Utils::SmallString>
MockSqliteReadStatement::value<Utils::SmallString>(const int&);

View File

@@ -0,0 +1,41 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include "googletest.h"
#include <sqlitetransaction.h>
class MockSqliteTransactionBackend : public Sqlite::TransactionInterface
{
public:
MOCK_METHOD0(deferredBegin, void ());
MOCK_METHOD0(immediateBegin, void ());
MOCK_METHOD0(exclusiveBegin, void ());
MOCK_METHOD0(commit, void ());
MOCK_METHOD0(rollback, void ());
};

View File

@@ -55,8 +55,20 @@ public:
MOCK_METHOD2(write,
void (uint, Utils::SmallStringView));
MOCK_METHOD2(write,
void (Utils::SmallStringView, Utils::SmallStringView));
MOCK_METHOD1(write,
void (Utils::SmallStringView));
MOCK_METHOD1(write,
void (long long));
MOCK_METHOD1(write,
void (int));
MOCK_METHOD2(write,
void (int, int));
Utils::SmallString sqlStatement;
};

View File

@@ -36,7 +36,7 @@ public:
void());
MOCK_METHOD2(addFiles,
void(const Utils::PathStringVector &filePaths,
void(const ClangBackEnd::FilePathIds &filePathIds,
const Utils::SmallStringVector &arguments));
MOCK_METHOD1(addUnsavedFiles,
@@ -53,4 +53,7 @@ public:
MOCK_CONST_METHOD0(sourceFiles,
const ClangBackEnd::FilePathIds &());
MOCK_CONST_METHOD0(usedDefines,
const ClangBackEnd::UsedDefines &());
};

View File

@@ -27,6 +27,8 @@
#include "googletest.h"
#include "mocksqlitedatabase.h"
#include <symbolstorageinterface.h>
class MockSymbolStorage : public ClangBackEnd::SymbolStorageInterface
@@ -35,4 +37,10 @@ public:
MOCK_METHOD2(addSymbolsAndSourceLocations,
void(const ClangBackEnd::SymbolEntries &symbolEentries,
const ClangBackEnd::SourceLocationEntries &sourceLocations));
MOCK_METHOD2(insertOrUpdateProjectPart,
void(Utils::SmallStringView projectPartName,
const Utils::SmallStringVector &commandLineArgument));
MOCK_METHOD2(updateProjectPartSources,
void(Utils::SmallStringView projectPartName,
const ClangBackEnd::FilePathIds &sourceFilePathIds));
};

View File

@@ -26,13 +26,17 @@
#include "googletest.h"
#include "fakeprocess.h"
#include "mockfilepathcaching.h"
#include "mockpchgeneratornotifier.h"
#include "testenvironment.h"
#include <refactoringdatabaseinitializer.h>
#include <filepathcaching.h>
#include <pchcreator.h>
#include <pchgenerator.h>
#include <sqlitedatabase.h>
#include <QFileInfo>
namespace {
@@ -53,11 +57,15 @@ using UnitTests::EndsWith;
class PchCreator: public ::testing::Test
{
protected:
void SetUp();
ClangBackEnd::FilePathId id(Utils::SmallStringView path);
ClangBackEnd::FilePathId id(ClangBackEnd::FilePathView path)
{
return filePathCache.filePathId(path);
}
protected:
NiceMock<MockFilePathCaching> filePathCache;
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
FilePath main1Path = TESTDATA_DIR "/includecollector_main3.cpp";
FilePath main2Path = TESTDATA_DIR "/includecollector_main2.cpp";
FilePath header1Path = TESTDATA_DIR "/includecollector_header1.h";
@@ -66,12 +74,12 @@ protected:
FilePath generatedFilePath = TESTDATA_DIR "/includecollector_generated_file.h";
ProjectPartContainer projectPart1{"project1",
{"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"},
{header1Path},
{main1Path}};
{id(header1Path)},
{id(main1Path)}};
ProjectPartContainer projectPart2{"project2",
{"-I", TESTDATA_DIR, "-x", "c++-header", "-Wno-pragma-once-outside-header"},
{header2Path},
{main2Path}};
{id(header2Path)},
{id(main2Path)}};
TestEnvironment environment;
FileContainer generatedFile{{TESTDATA_DIR, generatedFileName}, "#pragma once", {}};
NiceMock<MockPchGeneratorNotifier> mockPchGeneratorNotifier;
@@ -332,32 +340,5 @@ TEST_F(PchCreator, CreateProjectPartHeaderAndSourcesContent)
"#include \"" TESTDATA_DIR "/includecollector_main3.cpp\"\n"));
}
void PchCreator::SetUp()
{
ON_CALL(filePathCache, filePathId(Eq(FilePathView{TESTDATA_DIR "/includecollector_external1.h"})))
.WillByDefault(Return(FilePathId{1, 1}));
ON_CALL(filePathCache, filePathId(Eq(FilePathView{TESTDATA_DIR "/includecollector_external2.h"})))
.WillByDefault(Return(FilePathId{1, 2}));
ON_CALL(filePathCache, filePathId(Eq(FilePathView{TESTDATA_DIR "/includecollector_external3.h"})))
.WillByDefault(Return(FilePathId{1, 3}));
ON_CALL(filePathCache, filePathId(Eq(header1Path)))
.WillByDefault(Return(FilePathId{1, 4}));
ON_CALL(filePathCache, filePathId(Eq(header2Path)))
.WillByDefault(Return(FilePathId{1, 5}));
ON_CALL(filePathCache, filePath(Eq(FilePathId{1, 1})))
.WillByDefault(Return(FilePath{TESTDATA_DIR "/includecollector_external1.h"}));
ON_CALL(filePathCache, filePath(Eq(FilePathId{1, 2})))
.WillByDefault(Return(FilePath{TESTDATA_DIR "/includecollector_external2.h"}));
ON_CALL(filePathCache, filePath(Eq(FilePathId{1, 3})))
.WillByDefault(Return(FilePath{TESTDATA_DIR "/includecollector_external3.h"}));
ON_CALL(filePathCache, filePath(Eq(FilePathId{1, 4})))
.WillByDefault(Return(FilePath{header1Path}));
ON_CALL(filePathCache, filePath(Eq(FilePathId{1, 5})))
.WillByDefault(Return(FilePath{header2Path}));
}
ClangBackEnd::FilePathId PchCreator::id(Utils::SmallStringView path)
{
return filePathCache.filePathId(ClangBackEnd::FilePathView(path));
}
}

View File

@@ -31,6 +31,8 @@
#include <pchmanagerclient.h>
#include <pchmanagerprojectupdater.h>
#include <filepathcaching.h>
#include <refactoringdatabaseinitializer.h>
#include <precompiledheadersupdatedmessage.h>
#include <removepchprojectpartsmessage.h>
#include <updatepchprojectpartsmessage.h>
@@ -49,7 +51,10 @@ protected:
MockPchManagerServer mockPchManagerServer;
ClangPchManager::PchManagerClient client;
MockPchManagerNotifier mockPchManagerNotifier{client};
ClangPchManager::PchManagerProjectUpdater projectUpdater{mockPchManagerServer, client};
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
ClangPchManager::PchManagerProjectUpdater projectUpdater{mockPchManagerServer, client, filePathCache};
Utils::SmallString projectPartId{"projectPartId"};
Utils::SmallString pchFilePath{"/path/to/pch"};
PrecompiledHeadersUpdatedMessage message{{{projectPartId.clone(), pchFilePath.clone()}}};

View File

@@ -94,8 +94,8 @@ TEST_F(PchManagerClientServerInProcess, SendUpdatePchProjectPartsMessage)
{
ProjectPartContainer projectPart2{"projectPartId",
{"-x", "c++-header", "-Wno-pragma-once-outside-header"},
{TESTDATA_DIR "/includecollector_header.h"},
{TESTDATA_DIR "/includecollector_main.cpp"}};
{{1, 1}},
{{1, 2}}};
FileContainer fileContainer{{"/path/to/", "file"}, "content", {}};
UpdatePchProjectPartsMessage message{{projectPart2}, {fileContainer}};

View File

@@ -30,21 +30,14 @@
#include "mockpchcreator.h"
#include "mockprojectparts.h"
#include <filepathcaching.h>
#include <pchmanagerserver.h>
#include <precompiledheadersupdatedmessage.h>
#include <refactoringdatabaseinitializer.h>
#include <removepchprojectpartsmessage.h>
#include <updatepchprojectpartsmessage.h>
namespace {
using testing::ElementsAre;
using testing::UnorderedElementsAre;
using testing::ByMove;
using testing::NiceMock;
using testing::Return;
using testing::_;
using testing::IsEmpty;
using Utils::PathString;
using Utils::SmallString;
using ClangBackEnd::V2::FileContainer;
@@ -54,12 +47,18 @@ using ClangBackEnd::TaskFinishStatus;
class PchManagerServer : public ::testing::Test
{
void SetUp() override;
ClangBackEnd::FilePathId id(Utils::SmallStringView path) const
{
return filePathCache.filePathId(ClangBackEnd::FilePathView(path));
}
protected:
NiceMock<MockPchCreator> mockPchCreator;
NiceMock<MockClangPathWatcher> mockClangPathWatcher;
NiceMock<MockProjectParts> mockProjectParts;
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockPchCreator, mockProjectParts};
NiceMock<MockPchManagerClient> mockPchManagerClient;
SmallString projectPartId1 = "project1";
@@ -71,12 +70,12 @@ protected:
std::vector<ClangBackEnd::IdPaths> idPaths = {{projectPartId1, {{1, 1}, {1, 2}}}};
ProjectPartContainer projectPart1{projectPartId1.clone(),
{"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"},
{header1Path.clone()},
{main1Path.clone()}};
{id(header1Path)},
{id(main1Path)}};
ProjectPartContainer projectPart2{projectPartId2.clone(),
{"-x", "c++-header", "-Wno-pragma-once-outside-header"},
{header2Path.clone()},
{main2Path.clone()}};
{id(header2Path)},
{id(main2Path)}};
std::vector<ProjectPartContainer> projectParts{projectPart1, projectPart2};
FileContainer generatedFile{{"/path/to/", "file"}, "content", {}};
ClangBackEnd::UpdatePchProjectPartsMessage updatePchProjectPartsMessage{Utils::clone(projectParts),

View File

@@ -36,23 +36,29 @@ using testing::UnorderedElementsAre;
using testing::IsEmpty;
using ClangBackEnd::V2::ProjectPartContainer;
using ClangBackEnd::FilePathId;
class ProjectParts : public testing::Test
{
protected:
ClangBackEnd::ProjectParts projectParts;
FilePathId firstHeader{1, 1};
FilePathId secondHeader{1, 2};
FilePathId firstSource{1, 11};
FilePathId secondSource{1, 12};
FilePathId thirdSource{1, 13};
ProjectPartContainer projectPartContainer1{"id",
{"-DUNIX", "-O2"},
{"headers1.h", "header2.h"},
{"source1.cpp", "source2.cpp"}};
{firstHeader, secondHeader},
{firstSource, secondSource}};
ProjectPartContainer updatedProjectPartContainer1{"id",
{"-DUNIX", "-O2"},
{"headers1.h", "header2.h"},
{"source1.cpp", "source2.cpp", "source3.cpp" }};
{firstHeader, secondHeader},
{firstSource, secondSource, thirdSource}};
ProjectPartContainer projectPartContainer2{"id2",
{"-DUNIX", "-O2"},
{"headers1.h", "header2.h"},
{"source1.cpp", "source2.cpp"}};
{firstHeader, secondHeader},
{firstSource, secondSource}};
};
TEST_F(ProjectParts, GetNoProjectPartsForAddingEmptyProjectParts)

View File

@@ -31,14 +31,18 @@
#include <pchmanagerprojectupdater.h>
#include <filepathcaching.h>
#include <pchmanagerclient.h>
#include <precompiledheadersupdatedmessage.h>
#include <refactoringdatabaseinitializer.h>
#include <removepchprojectpartsmessage.h>
#include <updatepchprojectpartsmessage.h>
#include <cpptools/compileroptionsbuilder.h>
#include <cpptools/projectpart.h>
#include <utils/algorithm.h>
namespace {
using testing::_;
@@ -54,13 +58,43 @@ using CppTools::CompilerOptionsBuilder;
class ProjectUpdater : public testing::Test
{
protected:
void SetUp() override;
ClangBackEnd::FilePathId filePathId(Utils::SmallStringView path)
{
return filePathCache.filePathId(ClangBackEnd::FilePathView{path});
}
ClangBackEnd::FilePathIds filePathIds(const Utils::PathStringVector &paths)
{
return filePathCache.filePathIds(Utils::transform(paths, [] (const Utils::PathString &path) {
return ClangBackEnd::FilePathView(path);
}));
}
void SetUp() override
{
projectPart.files.push_back(header1ProjectFile);
projectPart.files.push_back(header2ProjectFile);
projectPart.files.push_back(source1ProjectFile);
projectPart.files.push_back(source2ProjectFile);
projectPart.displayName = QString(projectPartId);
Utils::SmallStringVector arguments{ClangPchManager::ProjectUpdater::compilerArguments(
&projectPart)};
expectedContainer = {projectPartId.clone(),
arguments.clone(),
{filePathId(headerPaths[1])},
{filePathIds(sourcePaths)}};
}
protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
ClangPchManager::PchManagerClient pchManagerClient;
MockPchManagerNotifier mockPchManagerNotifier{pchManagerClient};
NiceMock<MockPchManagerServer> mockPchManagerServer;
ClangPchManager::ProjectUpdater updater{mockPchManagerServer};
ClangPchManager::ProjectUpdater updater{mockPchManagerServer, filePathCache};
Utils::SmallString projectPartId{"project1"};
Utils::SmallString projectPartId2{"project2"};
Utils::PathStringVector headerPaths = {"/path/to/header1.h", "/path/to/header2.h"};
@@ -97,7 +131,7 @@ TEST_F(ProjectUpdater, CallRemovePchProjectParts)
TEST_F(ProjectUpdater, CallPrecompiledHeaderRemovedInPchManagerProjectUpdater)
{
ClangPchManager::PchManagerProjectUpdater pchUpdater{mockPchManagerServer, pchManagerClient};
ClangPchManager::PchManagerProjectUpdater pchUpdater{mockPchManagerServer, pchManagerClient, filePathCache};
ClangBackEnd::RemovePchProjectPartsMessage message{{projectPartId, projectPartId2}};
EXPECT_CALL(mockPchManagerNotifier, precompiledHeaderRemoved(projectPartId.toQString()));
@@ -129,21 +163,6 @@ TEST_F(ProjectUpdater, CreateExcludedPaths)
ASSERT_THAT(excludedPaths, ElementsAre("/path/to/header1.h"));
}
void ProjectUpdater::SetUp()
{
projectPart.files.push_back(header1ProjectFile);
projectPart.files.push_back(header2ProjectFile);
projectPart.files.push_back(source1ProjectFile);
projectPart.files.push_back(source2ProjectFile);
projectPart.displayName = QString(projectPartId);
Utils::SmallStringVector arguments{ClangPchManager::ProjectUpdater::compilerArguments(
&projectPart)};
expectedContainer = {projectPartId.clone(),
arguments.clone(),
{headerPaths[1]},
sourcePaths.clone()};
}
}

View File

@@ -178,8 +178,8 @@ TEST_F(RefactoringClientServerInProcess, SendUpdatePchProjectPartsMessage)
{
ProjectPartContainer projectPart2{"projectPartId",
{"-x", "c++-header", "-Wno-pragma-once-outside-header"},
{TESTDATA_DIR "/includecollector_header.h"},
{TESTDATA_DIR "/includecollector_main.cpp"}};
{{1, 1}},
{{1, 2}}};
FileContainer fileContainer{{"/path/to/", "file"}, "content", {}};
UpdatePchProjectPartsMessage message{{projectPart2}, {fileContainer}};

View File

@@ -38,8 +38,7 @@ using Sqlite::Table;
class RefactoringDatabaseInitializer : public testing::Test
{
protected:
NiceMock<MockMutex> mockMutex;
NiceMock<MockSqliteDatabase> mockDatabase{mockMutex};
NiceMock<MockSqliteDatabase> mockDatabase;
Initializer initializer{mockDatabase};
};
@@ -68,7 +67,7 @@ TEST_F(RefactoringDatabaseInitializer, AddSourcesTable)
InSequence s;
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, directoryId INTEGER, sourceName TEXT, sourceType INTEGER)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sources_sourceName ON sources(sourceName)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sources_directoryId_sourceName ON sources(directoryId, sourceName)")));
initializer.createSourcesTable();
}
@@ -93,24 +92,36 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsTable)
initializer.createProjectPartsTable();
}
TEST_F(RefactoringDatabaseInitializer, AddprojectPartsSourcesTable)
{
InSequence s;
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, sourceId INTEGER)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON projectPartsSources(projectPartId)")));
initializer.createprojectPartsSourcesTable();
}
TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor)
{
InSequence s;
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
EXPECT_CALL(mockDatabase, immediateBegin());
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS symbols(symbolId INTEGER PRIMARY KEY, usr TEXT, symbolName TEXT)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_symbols_usr ON symbols(usr)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS locations(symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_locations_sourceId_line_column ON locations(sourceId, line, column)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sources(sourceId INTEGER PRIMARY KEY, directoryId INTEGER, sourceName TEXT, sourceType INTEGER)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sources_sourceName ON sources(sourceName)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE 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 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, compilerArguments TEXT)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, sourceId INTEGER)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON projectPartsSources(projectPartId)")));
EXPECT_CALL(mockDatabase, commit());
Initializer initializer{mockDatabase};
}

View File

@@ -82,6 +82,11 @@ protected:
void SetUp() override;
void TearDown() override;
ClangBackEnd::FilePathId filePathId(Utils::SmallStringView string)
{
return filePathCache.filePathId(ClangBackEnd::FilePathView{string});
}
protected:
NiceMock<MockRefactoringClient> mockRefactoringClient;
NiceMock<MockSymbolIndexing> mockSymbolIndexing;
@@ -296,8 +301,8 @@ TEST_F(RefactoringServer, UpdatePchProjectPartsCallsSymbolIndexingUpdateProjectP
{
ProjectPartContainers projectParts{{{"projectPartId",
{"-I", TESTDATA_DIR},
{"header1.h"},
{"main.cpp"}}}};
{filePathId("header1.h")},
{filePathId("main.cpp")}}}};
FileContainers unsaved{{{TESTDATA_DIR, "query_simplefunction.h"},
"void f();",
{}}};

View File

@@ -25,89 +25,81 @@
#include "googletest.h"
#include "mocksqlitetransactionbackend.h"
#include <sqlitetransaction.h>
#include <mocksqlitedatabase.h>
namespace {
using DeferredTransaction = Sqlite::DeferredTransaction<MockSqliteDatabase>;
using ImmediateTransaction = Sqlite::ImmediateTransaction<MockSqliteDatabase>;
using ExclusiveTransaction = Sqlite::ExclusiveTransaction<MockSqliteDatabase>;
using Sqlite::DeferredTransaction;
using Sqlite::ImmediateTransaction;
using Sqlite::ExclusiveTransaction;
class SqliteTransaction : public testing::Test
{
protected:
MockMutex mockMutex;
MockSqliteDatabase mockDatabase{mockMutex};
MockSqliteTransactionBackend mockTransactionBackend;
};
TEST_F(SqliteTransaction, DeferredTransactionCommit)
{
EXPECT_CALL(mockDatabase, databaseMutex());
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockTransactionBackend, deferredBegin());
EXPECT_CALL(mockTransactionBackend, commit());
DeferredTransaction transaction{mockDatabase};
DeferredTransaction transaction{mockTransactionBackend};
transaction.commit();
}
TEST_F(SqliteTransaction, DeferredTransactionCommitCallsInterface)
{
EXPECT_CALL(mockTransactionBackend, deferredBegin());
EXPECT_CALL(mockTransactionBackend, commit());
DeferredTransaction transaction{mockTransactionBackend};
transaction.commit();
}
TEST_F(SqliteTransaction, DeferredTransactionRollBack)
{
EXPECT_CALL(mockDatabase, databaseMutex());
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN")));
EXPECT_CALL(mockDatabase, execute(Eq("ROLLBACK")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockTransactionBackend, deferredBegin());
EXPECT_CALL(mockTransactionBackend, rollback());
DeferredTransaction transaction{mockDatabase};
DeferredTransaction transaction{mockTransactionBackend};
}
TEST_F(SqliteTransaction, ImmediateTransactionCommit)
{
EXPECT_CALL(mockDatabase, databaseMutex());
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockTransactionBackend, immediateBegin());
EXPECT_CALL(mockTransactionBackend, commit());
ImmediateTransaction transaction{mockDatabase};
ImmediateTransaction transaction{mockTransactionBackend};
transaction.commit();
}
TEST_F(SqliteTransaction, ImmediateTransactionRollBack)
{
EXPECT_CALL(mockDatabase, databaseMutex());
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
EXPECT_CALL(mockDatabase, execute(Eq("ROLLBACK")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockTransactionBackend, immediateBegin());
EXPECT_CALL(mockTransactionBackend, rollback());
ImmediateTransaction transaction{mockDatabase};
ImmediateTransaction transaction{mockTransactionBackend};
}
TEST_F(SqliteTransaction, ExclusiveTransactionCommit)
{
EXPECT_CALL(mockDatabase, databaseMutex());
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN EXCLUSIVE")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockTransactionBackend, exclusiveBegin());
EXPECT_CALL(mockTransactionBackend, commit());
ExclusiveTransaction transaction{mockDatabase};
ExclusiveTransaction transaction{mockTransactionBackend};
transaction.commit();
}
TEST_F(SqliteTransaction, ExclusiveTransactionRollBack)
{
EXPECT_CALL(mockDatabase, databaseMutex());
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN EXCLUSIVE")));
EXPECT_CALL(mockDatabase, execute(Eq("ROLLBACK")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockTransactionBackend, exclusiveBegin());
EXPECT_CALL(mockTransactionBackend, rollback());
ExclusiveTransaction transaction{mockDatabase};
ExclusiveTransaction transaction{mockTransactionBackend};
}
}

View File

@@ -42,8 +42,7 @@ using Sqlite::Table;
class StorageSqliteStatementFactory : public testing::Test
{
protected:
NiceMock<MockMutex> mockMutex;
NiceMock<MockSqliteDatabase> mockDatabase{mockMutex};
NiceMock<MockSqliteDatabase> mockDatabase;
StatementFactory factory{mockDatabase};
};
@@ -51,13 +50,11 @@ TEST_F(StorageSqliteStatementFactory, AddNewSymbolsTable)
{
InSequence s;
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
EXPECT_CALL(mockDatabase, immediateBegin());
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_usr_symbolName ON newSymbols(usr, symbolName)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_symbolId ON newSymbols(symbolId)")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockDatabase, commit());
factory.createNewSymbolsTable();
}
@@ -66,22 +63,18 @@ TEST_F(StorageSqliteStatementFactory, AddNewLocationsTable)
{
InSequence s;
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
EXPECT_CALL(mockDatabase, immediateBegin());
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newLocations(temporarySymbolId INTEGER, symbolId INTEGER, line INTEGER, column INTEGER, sourceId INTEGER)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newLocations_sourceId ON newLocations(sourceId)")));
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockMutex, unlock());
EXPECT_CALL(mockDatabase, commit());
factory.createNewLocationsTable();
}
TEST_F(StorageSqliteStatementFactory, AddTablesInConstructor)
{
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE"))).Times(2);
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT"))).Times(2);
EXPECT_CALL(mockMutex, lock()).Times(2);
EXPECT_CALL(mockMutex, unlock()).Times(2);
EXPECT_CALL(mockDatabase, immediateBegin()).Times(2);
EXPECT_CALL(mockDatabase, commit()).Times(2);
EXPECT_CALL(mockDatabase, execute(Eq("CREATE TEMPORARY TABLE newSymbols(temporarySymbolId INTEGER PRIMARY KEY, symbolId INTEGER, usr TEXT, symbolName TEXT)")));
EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_newSymbols_usr_symbolName ON newSymbols(usr, symbolName)")));
@@ -152,5 +145,40 @@ TEST_F(StorageSqliteStatementFactory, DeleteNewLocationsTableStatement)
Eq("DELETE FROM newLocations"));
}
TEST_F(StorageSqliteStatementFactory, InsertProjectPart)
{
ASSERT_THAT(factory.insertProjectPart.sqlStatement,
Eq("INSERT OR IGNORE INTO projectParts(projectPartName, compilerArguments) VALUES (?,?)"));
}
TEST_F(StorageSqliteStatementFactory, UpdateProjectPart)
{
ASSERT_THAT(factory.updateProjectPart.sqlStatement,
Eq("UPDATE projectParts SET compilerArguments = ? WHERE projectPartName = ?"));
}
TEST_F(StorageSqliteStatementFactory, GetProjectPartIdForProjectPartName)
{
ASSERT_THAT(factory.getProjectPartId.sqlStatement,
Eq("SELECT projectPartId FROM projectParts WHERE projectPartName = ?"));
}
TEST_F(StorageSqliteStatementFactory, DeleteAllProjectPartsSourcesWithProjectPartId)
{
ASSERT_THAT(factory.deleteAllProjectPartsSourcesWithProjectPartId.sqlStatement,
Eq("DELETE FROM projectPartsSources WHERE projectPartId = ?"));
}
TEST_F(StorageSqliteStatementFactory, InsertProjectPartsSources)
{
ASSERT_THAT(factory.insertProjectPartSources.sqlStatement,
Eq("INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?)"));
}
TEST_F(StorageSqliteStatementFactory, CompileArgumentsForFileId)
{
ASSERT_THAT(factory.getCompileArgumentsForFileId.sqlStatement,
Eq("SELECT compilerArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?)"));
}
}

View File

@@ -27,6 +27,8 @@
#include "mockclangpathwatcher.h"
#include "mocksymbolscollector.h"
#include "mocksymbolstorage.h"
#include "mockfilepathcaching.h"
#include "mocksqlitetransactionbackend.h"
#include <symbolindexer.h>
#include <updatepchprojectpartsmessage.h>
@@ -34,17 +36,9 @@
namespace {
using testing::_;
using testing::Contains;
using testing::Field;
using testing::IsEmpty;
using testing::NiceMock;
using testing::Property;
using testing::Return;
using testing::ReturnRef;
using testing::Sequence;
using Utils::PathString;
using ClangBackEnd::FilePathIds;
using ClangBackEnd::FilePathView;
using ClangBackEnd::V2::ProjectPartContainer;
using ClangBackEnd::V2::ProjectPartContainers;
using ClangBackEnd::V2::FileContainers;
@@ -54,6 +48,13 @@ using ClangBackEnd::SourceLocationEntries;
using ClangBackEnd::SourceLocationEntry;
using ClangBackEnd::SymbolType;
MATCHER_P2(IsFileId, directoryId, fileNameId,
std::string(negation ? "isn't " : "is ")
+ PrintToString(ClangBackEnd::FilePathId(directoryId, fileNameId)))
{
return arg == ClangBackEnd::FilePathId(directoryId, fileNameId);
}
class SymbolIndexer : public testing::Test
{
protected:
@@ -61,52 +62,55 @@ protected:
{
ON_CALL(mockCollector, symbols()).WillByDefault(ReturnRef(symbolEntries));
ON_CALL(mockCollector, sourceLocations()).WillByDefault(ReturnRef(sourceLocations));
ON_CALL(mockCollector, sourceFiles()).WillByDefault(ReturnRef(sourceFileIds));
}
protected:
PathString main1Path = TESTDATA_DIR "/includecollector_main3.cpp";
PathString main2Path = TESTDATA_DIR "/includecollector_main2.cpp";
PathString header1Path = TESTDATA_DIR "/includecollector_header1.h";
PathString header2Path = TESTDATA_DIR "/includecollector_header2.h";
ClangBackEnd::FilePathId main1PathId{1, 1};
ClangBackEnd::FilePathId main2PathId{1, 2};
ClangBackEnd::FilePathId header2PathId{1, 12};
ClangBackEnd::FilePathId header1PathId{1, 11};
PathString generatedFileName = "includecollector_generated_file.h";
PathString generatedFilePath = TESTDATA_DIR "/includecollector_generated_file.h";
ClangBackEnd::FilePathId generatedFilePathId{1, 21};
ProjectPartContainer projectPart1{"project1",
{"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"},
{header1Path.clone()},
{main1Path.clone()}};
{header1PathId},
{main1PathId}};
ProjectPartContainer projectPart2{"project2",
{"-I", TESTDATA_DIR, "-x", "c++-header", "-Wno-pragma-once-outside-header"},
{header2Path.clone()},
{main2Path.clone()}};
{header2PathId},
{main2PathId}};
FileContainers unsaved{{{TESTDATA_DIR, "query_simplefunction.h"},
"void f();",
{}}};
SymbolEntries symbolEntries{{1, {"function", "function"}}};
SourceLocationEntries sourceLocations{{1, {1, 1}, {42, 23}, SymbolType::Declaration}};
FilePathIds sourceFileIds{{1, 1}, {42, 23}};
NiceMock<MockSqliteTransactionBackend> mockSqliteTransactionBackend;
NiceMock<MockSymbolsCollector> mockCollector;
NiceMock<MockSymbolStorage> mockStorage;
NiceMock<MockClangPathWatcher> mockPathWatcher;
ClangBackEnd::SymbolIndexer indexer{mockCollector, mockStorage, mockPathWatcher};
NiceMock<MockFilePathCaching> mockFilePathCaching;
ClangBackEnd::SymbolIndexer indexer{mockCollector, mockStorage, mockPathWatcher, mockFilePathCaching, mockSqliteTransactionBackend};
};
TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector)
{
EXPECT_CALL(mockCollector, addFiles(projectPart1.sourcePaths(), projectPart1.arguments()));
EXPECT_CALL(mockCollector, addFiles(projectPart1.sourcePathIds(), projectPart1.arguments()));
indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsClearInCollector)
{
EXPECT_CALL(mockCollector, clear());
EXPECT_CALL(mockCollector, clear()).Times(2);
indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved));
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollectorForEveryProjectPart)
{
EXPECT_CALL(mockCollector, addFiles(_, _))
.Times(2);
EXPECT_CALL(mockCollector, addFiles(_, _)).Times(2);
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
@@ -121,37 +125,55 @@ TEST_F(SymbolIndexer, UpdateProjectPartsDoesNotCallAddFilesInCollectorForEmptyEv
TEST_F(SymbolIndexer, UpdateProjectPartsCallscollectSymbolsInCollector)
{
EXPECT_CALL(mockCollector, collectSymbols());
EXPECT_CALL(mockCollector, collectSymbols()).Times(2);;
indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved));
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsSymbolsInCollector)
{
EXPECT_CALL(mockCollector, symbols());
EXPECT_CALL(mockCollector, symbols()).Times(2);
indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved));
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsSourceLocationsInCollector)
{
EXPECT_CALL(mockCollector, sourceLocations());
EXPECT_CALL(mockCollector, sourceLocations()).Times(2);
indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved));
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddUnsavedFilesInCollector)
{
EXPECT_CALL(mockCollector, addUnsavedFiles(unsaved));
EXPECT_CALL(mockCollector, addUnsavedFiles(unsaved)).Times(2);
indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved));
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddSymbolsAndSourceLocationsInStorage)
{
EXPECT_CALL(mockStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations));
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(2);
EXPECT_CALL(mockStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)).Times(2);
EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(2);
indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved));
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartsInStorage)
{
EXPECT_CALL(mockStorage, insertOrUpdateProjectPart(Eq("project1"), ElementsAre("-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header")));
EXPECT_CALL(mockStorage, insertOrUpdateProjectPart(Eq("project2"), ElementsAre("-I", TESTDATA_DIR, "-x", "c++-header", "-Wno-pragma-once-outside-header")));
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartSources)
{
EXPECT_CALL(mockStorage, updateProjectPartSources(Eq("project1"), ElementsAre(IsFileId(1, 1), IsFileId(42, 23))));
EXPECT_CALL(mockStorage, updateProjectPartSources(Eq("project2"), ElementsAre(IsFileId(1, 1), IsFileId(42, 23))));
indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved));
}
TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrder)
@@ -162,7 +184,11 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrder)
EXPECT_CALL(mockCollector, addFiles(_, _));
EXPECT_CALL(mockCollector, addUnsavedFiles(unsaved));
EXPECT_CALL(mockCollector, collectSymbols());
EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin());
EXPECT_CALL(mockStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations));
EXPECT_CALL(mockStorage, insertOrUpdateProjectPart(_, _));
EXPECT_CALL(mockStorage, updateProjectPartSources(_, _));
EXPECT_CALL(mockSqliteTransactionBackend, commit());
indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved));
}
@@ -171,7 +197,7 @@ TEST_F(SymbolIndexer, CallSetNotifier)
{
EXPECT_CALL(mockPathWatcher, setNotifier(_));
ClangBackEnd::SymbolIndexer indexer{mockCollector, mockStorage, mockPathWatcher};
ClangBackEnd::SymbolIndexer indexer{mockCollector, mockStorage, mockPathWatcher, mockFilePathCaching, mockSqliteTransactionBackend};
}
}

View File

@@ -72,7 +72,10 @@ MATCHER_P3(IsLocation, filePathId, line, column,
class SymbolIndexing : public testing::Test
{
protected:
FilePathId filePathId(Utils::SmallString filePath);
FilePathId filePathId(Utils::SmallStringView filePath)
{
return filePathCache.filePathId(ClangBackEnd::FilePathView{filePath});
}
protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
@@ -85,7 +88,7 @@ protected:
ProjectPartContainer projectPart1{"project1",
{"cc", "-I", TESTDATA_DIR, "-std=c++1z"},
{},
{main1Path.clone()}};
{filePathId(main1Path)}};
};
TEST_F(SymbolIndexing, Locations)
@@ -110,9 +113,6 @@ TEST_F(SymbolIndexing, DISABLED_TemplateFunction)
IsLocation(filePathId(TESTDATA_DIR "/symbolindexing_main1.cpp"), 6, 5)));
}
ClangBackEnd::FilePathId SymbolIndexing::filePathId(Utils::SmallString filePath)
{
return filePathCache.filePathId(ClangBackEnd::FilePathView{filePath});
}
}

View File

@@ -52,11 +52,37 @@ using ClangBackEnd::SourceLocationEntry;
using ClangBackEnd::SymbolEntry;
using ClangBackEnd::SymbolType;
using ClangBackEnd::SymbolIndex;
using ClangBackEnd::UsedDefine;
using Sqlite::Database;
namespace {
MATCHER_P5(IsSourceLocationEntry, symbolId, filePathId, line, column, symbolType,
std::string(negation ? "isn't" : "is")
+ PrintToString(SourceLocationEntry{symbolId, filePathId, {line, column}, symbolType})
)
{
const SourceLocationEntry &entry = arg;
return entry.filePathId == filePathId
&& entry.lineColumn.line == line
&& entry.lineColumn.column == column
&& entry.symbolType == symbolType
&& entry.symbolId == symbolId;
}
MATCHER_P2(HasLineColumn, line, column,
std::string(negation ? "isn't" : "is")
+ PrintToString(Utils::LineColumn{line, column})
)
{
const SourceLocationEntry &entry = arg;
return entry.lineColumn.line == line
&& entry.lineColumn.column == column;
}
class SymbolsCollector : public testing::Test
{
protected:
@@ -65,7 +91,15 @@ protected:
return filePathCache.filePathId(ClangBackEnd::FilePathView{string});
}
SymbolIndex symbolIdForSymbolName(const Utils::SmallString &symbolName);
SymbolIndex symbolId(const Utils::SmallString &symbolName)
{
for (const auto &entry : collector.symbols()) {
if (entry.second.symbolName == symbolName)
return entry.first;
}
return 0;
}
protected:
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
@@ -76,7 +110,7 @@ protected:
TEST_F(SymbolsCollector, CollectSymbolName)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_simple.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_simple.cpp")}, {"cc"});
collector.collectSymbols();
@@ -87,33 +121,31 @@ TEST_F(SymbolsCollector, CollectSymbolName)
TEST_F(SymbolsCollector, SymbolMatchesLocation)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_simple.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_simple.cpp")}, {"cc"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(
AllOf(Field(&SourceLocationEntry::symbolId, symbolIdForSymbolName("function")),
Field(&SourceLocationEntry::line, 1),
Field(&SourceLocationEntry::column, 6))));
AllOf(Field(&SourceLocationEntry::symbolId, symbolId("function")),
HasLineColumn(1, 6))));
}
TEST_F(SymbolsCollector, OtherSymboldMatchesLocation)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_simple.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_simple.cpp")}, {"cc"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(
AllOf(Field(&SourceLocationEntry::symbolId, symbolIdForSymbolName("function")),
Field(&SourceLocationEntry::line, 2),
Field(&SourceLocationEntry::column, 6))));
AllOf(Field(&SourceLocationEntry::symbolId, symbolId("function")),
HasLineColumn(2, 6))));
}
TEST_F(SymbolsCollector, CollectFilePath)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_simple.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_simple.cpp")}, {"cc"});
collector.collectSymbols();
@@ -126,41 +158,38 @@ TEST_F(SymbolsCollector, CollectFilePath)
TEST_F(SymbolsCollector, CollectLineColumn)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_simple.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_simple.cpp")}, {"cc"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(
AllOf(Field(&SourceLocationEntry::line, 1),
Field(&SourceLocationEntry::column, 6),
AllOf(HasLineColumn(1, 6),
Field(&SourceLocationEntry::symbolType, SymbolType::Declaration))));
}
TEST_F(SymbolsCollector, CollectReference)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_simple.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_simple.cpp")}, {"cc"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(
AllOf(Field(&SourceLocationEntry::line, 14),
Field(&SourceLocationEntry::column, 5),
AllOf(HasLineColumn(14, 5),
Field(&SourceLocationEntry::symbolType, SymbolType::DeclarationReference))));
}
TEST_F(SymbolsCollector, ReferencedSymboldMatchesLocation)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_simple.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_simple.cpp")}, {"cc"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(
AllOf(Field(&SourceLocationEntry::symbolId, symbolIdForSymbolName("function")),
Field(&SourceLocationEntry::line, 14),
Field(&SourceLocationEntry::column, 5))));
AllOf(Field(&SourceLocationEntry::symbolId, symbolId("function")),
HasLineColumn(14, 5))));
}
TEST_F(SymbolsCollector, DISABLED_ON_WINDOWS(CollectInUnsavedFile))
@@ -168,7 +197,7 @@ TEST_F(SymbolsCollector, DISABLED_ON_WINDOWS(CollectInUnsavedFile))
FileContainers unsaved{{{TESTDATA_DIR, "symbolscollector_generated_file.h"},
"void function();",
{}}};
collector.addFiles({TESTDATA_DIR "/symbolscollector_unsaved.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_unsaved.cpp")}, {"cc"});
collector.addUnsavedFiles(std::move(unsaved));
collector.collectSymbols();
@@ -180,7 +209,7 @@ TEST_F(SymbolsCollector, DISABLED_ON_WINDOWS(CollectInUnsavedFile))
TEST_F(SymbolsCollector, SourceFiles)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
collector.collectSymbols();
@@ -192,7 +221,7 @@ TEST_F(SymbolsCollector, SourceFiles)
TEST_F(SymbolsCollector, MainFileInSourceFiles)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
ASSERT_THAT(collector.sourceFiles(),
ElementsAre(filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")));
@@ -200,7 +229,7 @@ TEST_F(SymbolsCollector, MainFileInSourceFiles)
TEST_F(SymbolsCollector, ResetMainFileInSourceFiles)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
ASSERT_THAT(collector.sourceFiles(),
ElementsAre(filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")));
@@ -208,7 +237,7 @@ TEST_F(SymbolsCollector, ResetMainFileInSourceFiles)
TEST_F(SymbolsCollector, DontDuplicateSourceFiles)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
collector.collectSymbols();
collector.collectSymbols();
@@ -221,7 +250,7 @@ TEST_F(SymbolsCollector, DontDuplicateSourceFiles)
TEST_F(SymbolsCollector, ClearSourceFiles)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
collector.clear();
@@ -230,7 +259,7 @@ TEST_F(SymbolsCollector, ClearSourceFiles)
TEST_F(SymbolsCollector, ClearSymbols)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
collector.collectSymbols();
collector.clear();
@@ -240,7 +269,7 @@ TEST_F(SymbolsCollector, ClearSymbols)
TEST_F(SymbolsCollector, ClearSourceLocations)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
collector.collectSymbols();
collector.clear();
@@ -250,7 +279,7 @@ TEST_F(SymbolsCollector, ClearSourceLocations)
TEST_F(SymbolsCollector, DontCollectSymbolsAfterFilesAreCleared)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
collector.clear();
collector.collectSymbols();
@@ -260,7 +289,7 @@ TEST_F(SymbolsCollector, DontCollectSymbolsAfterFilesAreCleared)
TEST_F(SymbolsCollector, DontCollectSourceFilesAfterFilesAreCleared)
{
collector.addFiles({TESTDATA_DIR "/symbolscollector_main.cpp"}, {"cc"});
collector.addFiles({filePathId(TESTDATA_DIR "/symbolscollector_main.cpp")}, {"cc"});
collector.clear();
collector.collectSymbols();
@@ -268,14 +297,119 @@ TEST_F(SymbolsCollector, DontCollectSourceFilesAfterFilesAreCleared)
ASSERT_THAT(collector.sourceFiles(), IsEmpty());
}
SymbolIndex SymbolsCollector::symbolIdForSymbolName(const Utils::SmallString &symbolName)
TEST_F(SymbolsCollector, CollectDefines)
{
for (const auto &entry : collector.symbols()) {
if (entry.second.symbolName == symbolName)
return entry.first;
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.usedDefines(),
ElementsAre(Eq(UsedDefine{"DEFINED", fileId}),
Eq(UsedDefine{"IF_DEFINE", fileId}),
Eq(UsedDefine{"__clang__", fileId}),
Eq(UsedDefine{"IF_NOT_DEFINE", fileId}),
Eq(UsedDefine{"MACRO_EXPANSION", fileId}),
Eq(UsedDefine{"COMPILER_ARGUMENT", fileId})));
}
return 0;
TEST_F(SymbolsCollector, CollectMacroDefinitionSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("IF_NOT_DEFINE"), fileId, 4, 9, SymbolType::MacroDefinition)));
}
TEST_F(SymbolsCollector, CollectMacroUsageInIfNotDefSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("IF_NOT_DEFINE"), fileId, 6, 9, SymbolType::MacroUsage)));
}
TEST_F(SymbolsCollector, CollectSecondMacroUsageInIfNotDefSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("IF_NOT_DEFINE"), fileId, 9, 9, SymbolType::MacroUsage)));
}
TEST_F(SymbolsCollector, CollectMacroUsageCompilerArgumentSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("COMPILER_ARGUMENT"), fileId, 12, 9, SymbolType::MacroUsage)));
}
TEST_F(SymbolsCollector, CollectMacroUsageInIfDefSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("IF_DEFINE"), fileId, 17, 8, SymbolType::MacroUsage)));
}
TEST_F(SymbolsCollector, CollectMacroUsageInDefinedSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("DEFINED"), fileId, 22, 13, SymbolType::MacroUsage)));
}
TEST_F(SymbolsCollector, CollectMacroUsageExpansionSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("MACRO_EXPANSION"), fileId, 27, 10, SymbolType::MacroUsage)));
}
TEST_F(SymbolsCollector, CollectMacroUsageUndefSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("UN_DEFINE"), fileId, 34, 8, SymbolType::MacroUndefinition)));
}
TEST_F(SymbolsCollector, CollectMacroUsageBuiltInSourceLocation)
{
auto fileId = filePathId(TESTDATA_DIR "/symbolscollector_defines.h");
collector.addFiles({fileId}, {"cc", "-DCOMPILER_ARGUMENT"});
collector.collectSymbols();
ASSERT_THAT(collector.sourceLocations(),
Contains(IsSourceLocationEntry(symbolId("__clang__"), fileId, 29, 9, SymbolType::MacroUsage)));
}
}

View File

@@ -55,13 +55,9 @@ using Storage = ClangBackEnd::SymbolStorage<StatementFactory>;
class SymbolStorage : public testing::Test
{
protected:
void SetUp();
protected:
MockFilePathCaching filePathCache;
NiceMock<MockMutex> mockMutex;
NiceMock<MockSqliteDatabase> mockDatabase{mockMutex};
NiceMock<MockSqliteDatabase> mockDatabase;
StatementFactory statementFactory{mockDatabase};
MockSqliteWriteStatement &insertSymbolsToNewSymbolsStatement = statementFactory.insertSymbolsToNewSymbolsStatement;
MockSqliteWriteStatement &insertLocationsToNewLocationsStatement = statementFactory.insertLocationsToNewLocationsStatement;
@@ -73,6 +69,11 @@ protected:
MockSqliteWriteStatement &insertNewLocationsInLocationsStatement = statementFactory.insertNewLocationsInLocationsStatement;
MockSqliteWriteStatement &deleteNewSymbolsTableStatement = statementFactory.deleteNewSymbolsTableStatement;
MockSqliteWriteStatement &deleteNewLocationsTableStatement = statementFactory.deleteNewLocationsTableStatement;
MockSqliteWriteStatement &insertProjectPart = statementFactory.insertProjectPart;
MockSqliteWriteStatement &updateProjectPart = statementFactory.updateProjectPart;
MockSqliteReadStatement &getProjectPartId = statementFactory.getProjectPartId;
MockSqliteWriteStatement &deleteAllProjectPartsSourcesWithProjectPartId = statementFactory.deleteAllProjectPartsSourcesWithProjectPartId;
MockSqliteWriteStatement &insertProjectPartSources = statementFactory.insertProjectPartSources;
SymbolEntries symbolEntries{{1, {"functionUSR", "function"}},
{2, {"function2USR", "function2"}}};
SourceLocationEntries sourceLocations{{1, {1, 3}, {42, 23}, SymbolType::Declaration},
@@ -143,8 +144,6 @@ TEST_F(SymbolStorage, AddSymbolsAndSourceLocationsCallsWrite)
{
InSequence sequence;
EXPECT_CALL(mockMutex, lock());
EXPECT_CALL(mockDatabase, execute(Eq("BEGIN IMMEDIATE")));
EXPECT_CALL(insertSymbolsToNewSymbolsStatement, write(_, _, _)).Times(2);
EXPECT_CALL(insertLocationsToNewLocationsStatement, write(1, 42, 23, 3));
EXPECT_CALL(insertLocationsToNewLocationsStatement, write(2, 7, 11, 4));
@@ -155,14 +154,56 @@ TEST_F(SymbolStorage, AddSymbolsAndSourceLocationsCallsWrite)
EXPECT_CALL(insertNewLocationsInLocationsStatement, execute());
EXPECT_CALL(deleteNewSymbolsTableStatement, execute());
EXPECT_CALL(deleteNewLocationsTableStatement, execute());
EXPECT_CALL(mockDatabase, execute(Eq("COMMIT")));
EXPECT_CALL(mockMutex, unlock());
storage.addSymbolsAndSourceLocations(symbolEntries, sourceLocations);
}
void SymbolStorage::SetUp()
TEST_F(SymbolStorage, ConvertStringsToJson)
{
}
Utils::SmallStringVector strings{"foo", "bar", "foo"};
auto jsonText = storage.toJson(strings);
ASSERT_THAT(jsonText, Eq("[\"foo\",\"bar\",\"foo\"]"));
}
TEST_F(SymbolStorage, InsertProjectPart)
{
InSequence sequence;
ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(1));
EXPECT_CALL(mockDatabase, setLastInsertedRowId(-1));
EXPECT_CALL(insertProjectPart, write(TypedEq<Utils::SmallStringView>("project"), TypedEq<Utils::SmallStringView>("[\"foo\"]")));
EXPECT_CALL(mockDatabase, lastInsertedRowId());
storage.insertOrUpdateProjectPart("project", {"foo"});
}
TEST_F(SymbolStorage, UpdateProjectPart)
{
InSequence sequence;
ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(-1));
EXPECT_CALL(mockDatabase, setLastInsertedRowId(-1));
EXPECT_CALL(insertProjectPart, write(TypedEq<Utils::SmallStringView>("project"), TypedEq<Utils::SmallStringView>("[\"foo\"]")));
EXPECT_CALL(mockDatabase, lastInsertedRowId());
EXPECT_CALL(updateProjectPart, write(TypedEq<Utils::SmallStringView>("[\"foo\"]"), TypedEq<Utils::SmallStringView>("project")));
storage.insertOrUpdateProjectPart("project", {"foo"});
}
TEST_F(SymbolStorage, UpdateProjectPartSources)
{
InSequence sequence;
EXPECT_CALL(getProjectPartId, valueReturnInt32(TypedEq<Utils::SmallStringView>("project"))).WillRepeatedly(Return(42));
EXPECT_CALL(deleteAllProjectPartsSourcesWithProjectPartId, write(TypedEq<int>(42)));
EXPECT_CALL(insertProjectPartSources, write(TypedEq<int>(42), TypedEq<int>(1)));
EXPECT_CALL(insertProjectPartSources, write(TypedEq<int>(42), TypedEq<int>(2)));
storage.updateProjectPartSources("project", {{1, 1}, {1, 2}});
}
}

View File

@@ -226,7 +226,8 @@ HEADERS += \
mocksymbolquery.h \
runprojectcreateorupdate-utility.h \
rundocumentparse-utility.h \
mocktimer.h
mocktimer.h \
mocksqlitetransactionbackend.h
!isEmpty(LIBCLANG_LIBS) {
HEADERS += \
chunksreportedmonitor.h \