forked from qt-creator/qt-creator
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:
@@ -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;
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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>;
|
||||
|
@@ -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;
|
||||
};
|
||||
|
@@ -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);
|
||||
|
@@ -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; }
|
||||
|
@@ -31,4 +31,8 @@
|
||||
|
||||
namespace Sqlite {
|
||||
|
||||
TransactionInterface::~TransactionInterface()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace Sqlite
|
||||
|
@@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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)
|
||||
{
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
}
|
||||
|
@@ -88,7 +88,7 @@ public:
|
||||
QtCreatorClangQueryFindFilter qtCreatorfindFilter{connectionClient.serverProxy(),
|
||||
qtCreatorSearch,
|
||||
refactoringClient};
|
||||
ProjectUpdater projectUpdate{connectionClient.serverProxy()};
|
||||
ProjectUpdater projectUpdate{connectionClient.serverProxy(), filePathCache};
|
||||
};
|
||||
|
||||
ClangRefactoringPlugin::ClangRefactoringPlugin()
|
||||
|
@@ -28,8 +28,9 @@
|
||||
namespace ClangRefactoring {
|
||||
|
||||
RefactoringProjectUpdater::RefactoringProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
|
||||
RefactoringClient &)
|
||||
: ClangPchManager::ProjectUpdater(server)
|
||||
RefactoringClient &,
|
||||
ClangBackEnd::FilePathCachingInterface &filePathCache)
|
||||
: ClangPchManager::ProjectUpdater(server, filePathCache)
|
||||
{
|
||||
|
||||
}
|
||||
|
@@ -35,7 +35,8 @@ class RefactoringProjectUpdater : public ClangPchManager::ProjectUpdater
|
||||
{
|
||||
public:
|
||||
RefactoringProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
|
||||
RefactoringClient &client);
|
||||
RefactoringClient &client,
|
||||
ClangBackEnd::FilePathCachingInterface &filePathCache);
|
||||
};
|
||||
|
||||
} // namespace ClangRefactoring
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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(
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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 ¯oNameToken,
|
||||
const clang::MacroDefinition ¯oDefinition) override
|
||||
{
|
||||
addUsedDefine(macroNameToken, macroDefinition);
|
||||
addMacroAsSymbol(macroNameToken,
|
||||
firstMacroInfo(macroDefinition.getLocalDirective()),
|
||||
SymbolType::MacroUsage);
|
||||
}
|
||||
|
||||
void Ifdef(clang::SourceLocation,
|
||||
const clang::Token ¯oNameToken,
|
||||
const clang::MacroDefinition ¯oDefinition) override
|
||||
{
|
||||
addUsedDefine( macroNameToken, macroDefinition);
|
||||
addMacroAsSymbol(macroNameToken,
|
||||
firstMacroInfo(macroDefinition.getLocalDirective()),
|
||||
SymbolType::MacroUsage);
|
||||
}
|
||||
|
||||
void Defined(const clang::Token ¯oNameToken,
|
||||
const clang::MacroDefinition ¯oDefinition,
|
||||
clang::SourceRange) override
|
||||
{
|
||||
addUsedDefine(macroNameToken, macroDefinition);
|
||||
addMacroAsSymbol(macroNameToken,
|
||||
firstMacroInfo(macroDefinition.getLocalDirective()),
|
||||
SymbolType::MacroUsage);
|
||||
}
|
||||
|
||||
void MacroDefined(const clang::Token ¯oNameToken,
|
||||
const clang::MacroDirective *macroDirective) override
|
||||
{
|
||||
addMacroAsSymbol(macroNameToken,
|
||||
firstMacroInfo(macroDirective),
|
||||
SymbolType::MacroDefinition);
|
||||
}
|
||||
|
||||
void MacroUndefined(const clang::Token ¯oNameToken,
|
||||
const clang::MacroDefinition ¯oDefinition,
|
||||
const clang::MacroDirective *) override
|
||||
{
|
||||
addMacroAsSymbol(macroNameToken,
|
||||
firstMacroInfo(macroDefinition.getLocalDirective()),
|
||||
SymbolType::MacroUndefinition);
|
||||
}
|
||||
|
||||
void MacroExpands(const clang::Token ¯oNameToken,
|
||||
const clang::MacroDefinition ¯oDefinition,
|
||||
clang::SourceRange,
|
||||
const clang::MacroArgs *) override
|
||||
{
|
||||
addUsedDefine(macroNameToken, macroDefinition);
|
||||
addMacroAsSymbol(macroNameToken,
|
||||
firstMacroInfo(macroDefinition.getLocalDirective()),
|
||||
SymbolType::MacroUsage);
|
||||
}
|
||||
|
||||
void addUsedDefine(const clang::Token ¯oNameToken,
|
||||
const clang::MacroDefinition ¯oDefinition)
|
||||
{
|
||||
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 ¯oNameToken,
|
||||
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;
|
||||
};
|
||||
|
||||
|
@@ -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));
|
||||
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
|
||||
};
|
||||
|
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
58
src/tools/clangrefactoringbackend/source/projectpartentry.h
Normal file
58
src/tools/clangrefactoringbackend/source/projectpartentry.h
Normal 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
|
@@ -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;
|
||||
}
|
||||
};
|
||||
|
@@ -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
|
||||
|
@@ -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 &)
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
@@ -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
|
||||
|
121
src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h
Normal file
121
src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h
Normal 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
|
66
src/tools/clangrefactoringbackend/source/useddefines.h
Normal file
66
src/tools/clangrefactoringbackend/source/useddefines.h
Normal 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
|
36
tests/unit/unittest/data/symbolscollector_defines.h
Normal file
36
tests/unit/unittest/data/symbolscollector_defines.h
Normal 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
|
@@ -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());
|
||||
|
@@ -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};
|
||||
};
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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 ¯o)
|
||||
} // 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;
|
||||
}
|
||||
|
@@ -61,6 +61,10 @@ std::ostream &operator<<(std::ostream &out, const Macro ¯o);
|
||||
} // 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;
|
||||
|
@@ -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));
|
||||
};
|
||||
|
||||
|
@@ -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)
|
||||
|
@@ -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&);
|
||||
|
41
tests/unit/unittest/mocksqlitetransactionbackend.h
Normal file
41
tests/unit/unittest/mocksqlitetransactionbackend.h
Normal 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 ());
|
||||
};
|
@@ -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;
|
||||
};
|
||||
|
@@ -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 &());
|
||||
};
|
||||
|
@@ -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));
|
||||
};
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
@@ -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()}}};
|
||||
|
@@ -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}};
|
||||
|
||||
|
@@ -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),
|
||||
|
@@ -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)
|
||||
|
@@ -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()};
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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}};
|
||||
|
||||
|
@@ -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};
|
||||
}
|
||||
|
@@ -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();",
|
||||
{}}};
|
||||
|
@@ -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};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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 = ?)"));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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};
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@@ -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)));
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -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}});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@@ -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 \
|
||||
|
Reference in New Issue
Block a user