diff --git a/src/libs/clangsupport/filepathstorage.h b/src/libs/clangsupport/filepathstorage.h index d8279c9c0b8..874374dfa5c 100644 --- a/src/libs/clangsupport/filepathstorage.h +++ b/src/libs/clangsupport/filepathstorage.h @@ -39,8 +39,6 @@ namespace ClangBackEnd { template class FilePathStorage { - using DeferredTransaction = Sqlite::DeferredTransaction; - using ImmediateTransaction = Sqlite::ImmediateTransaction; 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 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 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 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 fetchAllSources() { - DeferredTransaction transaction{m_statementFactory.database}; + Sqlite::DeferredTransaction transaction{m_statementFactory.database}; ReadStatement &statement = m_statementFactory.selectAllSources; diff --git a/src/libs/clangsupport/projectpartcontainerv2.cpp b/src/libs/clangsupport/projectpartcontainerv2.cpp index 3d0db58c2bc..a806a0f3da1 100644 --- a/src/libs/clangsupport/projectpartcontainerv2.cpp +++ b/src/libs/clangsupport/projectpartcontainerv2.cpp @@ -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; diff --git a/src/libs/clangsupport/projectpartcontainerv2.h b/src/libs/clangsupport/projectpartcontainerv2.h index 0772d1399b4..23be8e251bc 100644 --- a/src/libs/clangsupport/projectpartcontainerv2.h +++ b/src/libs/clangsupport/projectpartcontainerv2.h @@ -27,6 +27,8 @@ #include "clangsupport_global.h" +#include + #include 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; diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index 4d84e01f879..bd807acc3e0 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -39,13 +39,14 @@ public: RefactoringDatabaseInitializer(DatabaseType &database) : database(database) { - Sqlite::ImmediateTransaction 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; }; diff --git a/src/libs/sqlite/sqlitedatabase.cpp b/src/libs/sqlite/sqlitedatabase.cpp index 2d977c27b11..aff2ca7069d 100644 --- a/src/libs/sqlite/sqlitedatabase.cpp +++ b/src/libs/sqlite/sqlitedatabase.cpp @@ -116,7 +116,7 @@ void Database::execute(Utils::SmallStringView sqlStatement) void Database::initializeTables() { - ImmediateTransaction transaction(*this); + ImmediateTransaction transaction(*this); for (Table &table : m_sqliteTables) table.initialize(*this); diff --git a/src/libs/sqlite/sqlitedatabase.h b/src/libs/sqlite/sqlitedatabase.h index 50ae643029b..b45e99849c4 100644 --- a/src/libs/sqlite/sqlitedatabase.h +++ b/src/libs/sqlite/sqlitedatabase.h @@ -28,6 +28,7 @@ #include "sqlitedatabasebackend.h" #include "sqliteglobal.h" #include "sqlitetable.h" +#include "sqlitetransaction.h" #include @@ -36,10 +37,9 @@ namespace Sqlite { -class SQLITE_EXPORT Database +class SQLITE_EXPORT Database final : public TransactionInterface { template - 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; } diff --git a/src/libs/sqlite/sqlitetransaction.cpp b/src/libs/sqlite/sqlitetransaction.cpp index 2ee17131c25..b2ebd101a1a 100644 --- a/src/libs/sqlite/sqlitetransaction.cpp +++ b/src/libs/sqlite/sqlitetransaction.cpp @@ -31,4 +31,8 @@ namespace Sqlite { +TransactionInterface::~TransactionInterface() +{ +} + } // namespace Sqlite diff --git a/src/libs/sqlite/sqlitetransaction.h b/src/libs/sqlite/sqlitetransaction.h index d271728baea..49618692a4e 100644 --- a/src/libs/sqlite/sqlitetransaction.h +++ b/src/libs/sqlite/sqlitetransaction.h @@ -34,65 +34,77 @@ namespace Sqlite { class DatabaseBackend; class Database; -template +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 m_databaseLock; - Database &m_database; + TransactionInterface &m_interface; bool m_isAlreadyCommited = false; }; -template -class DeferredTransaction final : public AbstractTransaction +class DeferredTransaction final : public AbstractTransaction { public: - DeferredTransaction(Database &database) - : AbstractTransaction(database) + DeferredTransaction(TransactionInterface &interface) + : AbstractTransaction(interface) { - database.execute("BEGIN"); + interface.deferredBegin(); } }; -template -class ImmediateTransaction final : public AbstractTransaction +class ImmediateTransaction final : public AbstractTransaction { public: - ImmediateTransaction(Database &database) - : AbstractTransaction(database) + ImmediateTransaction(TransactionInterface &interface) + : AbstractTransaction(interface) { - database.execute("BEGIN IMMEDIATE"); + interface.immediateBegin(); } }; -template -class ExclusiveTransaction final : public AbstractTransaction +class ExclusiveTransaction final : public AbstractTransaction { public: - ExclusiveTransaction(Database &database) - : AbstractTransaction(database) + ExclusiveTransaction(TransactionInterface &interface) + : AbstractTransaction(interface) { - database.execute("BEGIN EXCLUSIVE"); + interface.exclusiveBegin(); } }; diff --git a/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp b/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp index 086b2fce8ef..c76342a0cd0 100644 --- a/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp +++ b/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp @@ -29,6 +29,10 @@ #include "pchmanagerclient.h" #include "qtcreatorprojectupdater.h" +#include +#include +#include + #include #include @@ -50,9 +54,14 @@ QString backendProcessPath() class ClangPchManagerPluginData { public: + Sqlite::Database database{Utils::PathString{Core::ICore::userResourcePath() + "/symbol-experimental-v1.db"}}; + ClangBackEnd::RefactoringDatabaseInitializer databaseInitializer{database}; + ClangBackEnd::FilePathCaching filePathCache{database}; PchManagerClient pchManagerClient; PchManagerConnectionClient connectionClient{&pchManagerClient}; - QtCreatorProjectUpdater projectUpdate{connectionClient.serverProxy(), pchManagerClient}; + QtCreatorProjectUpdater projectUpdate{connectionClient.serverProxy(), + pchManagerClient, + filePathCache}; }; std::unique_ptr ClangPchManagerPlugin::d; diff --git a/src/plugins/clangpchmanager/pchmanagerprojectupdater.cpp b/src/plugins/clangpchmanager/pchmanagerprojectupdater.cpp index d74ea2a7b06..f7b925049a8 100644 --- a/src/plugins/clangpchmanager/pchmanagerprojectupdater.cpp +++ b/src/plugins/clangpchmanager/pchmanagerprojectupdater.cpp @@ -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) { } diff --git a/src/plugins/clangpchmanager/pchmanagerprojectupdater.h b/src/plugins/clangpchmanager/pchmanagerprojectupdater.h index 0849554751e..470e12fe4a5 100644 --- a/src/plugins/clangpchmanager/pchmanagerprojectupdater.h +++ b/src/plugins/clangpchmanager/pchmanagerprojectupdater.h @@ -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); diff --git a/src/plugins/clangpchmanager/projectupdater.cpp b/src/plugins/clangpchmanager/projectupdater.cpp index 09c56cc79ba..205b35e24af 100644 --- a/src/plugins/clangpchmanager/projectupdater.cpp +++ b/src/plugins/clangpchmanager/projectupdater.cpp @@ -27,6 +27,7 @@ #include "pchmanagerclient.h" +#include #include #include #include @@ -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); } } diff --git a/src/plugins/clangpchmanager/projectupdater.h b/src/plugins/clangpchmanager/projectupdater.h index e207a88971f..a86e8d19702 100644 --- a/src/plugins/clangpchmanager/projectupdater.h +++ b/src/plugins/clangpchmanager/projectupdater.h @@ -28,6 +28,7 @@ #include "clangpchmanager_global.h" #include +#include 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 &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 diff --git a/src/plugins/clangpchmanager/qtcreatorprojectupdater.h b/src/plugins/clangpchmanager/qtcreatorprojectupdater.h index 44858ef9367..387e4573ad0 100644 --- a/src/plugins/clangpchmanager/qtcreatorprojectupdater.h +++ b/src/plugins/clangpchmanager/qtcreatorprojectupdater.h @@ -55,14 +55,16 @@ class QtCreatorProjectUpdater : public ProjectUpdaterType public: template 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(); } diff --git a/src/plugins/clangrefactoring/clangrefactoringplugin.cpp b/src/plugins/clangrefactoring/clangrefactoringplugin.cpp index f2b676853ad..3cc4496ce3a 100644 --- a/src/plugins/clangrefactoring/clangrefactoringplugin.cpp +++ b/src/plugins/clangrefactoring/clangrefactoringplugin.cpp @@ -88,7 +88,7 @@ public: QtCreatorClangQueryFindFilter qtCreatorfindFilter{connectionClient.serverProxy(), qtCreatorSearch, refactoringClient}; - ProjectUpdater projectUpdate{connectionClient.serverProxy()}; + ProjectUpdater projectUpdate{connectionClient.serverProxy(), filePathCache}; }; ClangRefactoringPlugin::ClangRefactoringPlugin() diff --git a/src/plugins/clangrefactoring/refactoringprojectupdater.cpp b/src/plugins/clangrefactoring/refactoringprojectupdater.cpp index 07a9e97163f..06a4af82d0d 100644 --- a/src/plugins/clangrefactoring/refactoringprojectupdater.cpp +++ b/src/plugins/clangrefactoring/refactoringprojectupdater.cpp @@ -28,8 +28,9 @@ namespace ClangRefactoring { RefactoringProjectUpdater::RefactoringProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server, - RefactoringClient &) - : ClangPchManager::ProjectUpdater(server) + RefactoringClient &, + ClangBackEnd::FilePathCachingInterface &filePathCache) + : ClangPchManager::ProjectUpdater(server, filePathCache) { } diff --git a/src/plugins/clangrefactoring/refactoringprojectupdater.h b/src/plugins/clangrefactoring/refactoringprojectupdater.h index 3debed0c4dc..f8b771187ec 100644 --- a/src/plugins/clangrefactoring/refactoringprojectupdater.h +++ b/src/plugins/clangrefactoring/refactoringprojectupdater.h @@ -35,7 +35,8 @@ class RefactoringProjectUpdater : public ClangPchManager::ProjectUpdater { public: RefactoringProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server, - RefactoringClient &client); + RefactoringClient &client, + ClangBackEnd::FilePathCachingInterface &filePathCache); }; } // namespace ClangRefactoring diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index 645e266db0b..c35a2b1f882 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -80,11 +80,18 @@ template 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 @@ -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(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(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; } diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.h b/src/tools/clangpchmanagerbackend/source/pchcreator.h index 26e591302f4..c7b2b1a943a 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.h @@ -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( diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index ef2b4641c5e..75739845cc8 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -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 diff --git a/src/tools/clangrefactoringbackend/source/clangtool.cpp b/src/tools/clangrefactoringbackend/source/clangtool.cpp index 61d3f968406..d7d740bd1a8 100644 --- a/src/tools/clangrefactoringbackend/source/clangtool.cpp +++ b/src/tools/clangrefactoringbackend/source/clangtool.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 commandLine(arguments.begin(), arguments.end()); + commandLine.push_back(std::string(filePath.name())); + + addFile(filePath.directory(), + filePath.name(), + {}, + std::move(commandLine)); + } +} + template void ClangTool::addFiles(const Container &filePaths, const Utils::SmallStringVector &arguments) diff --git a/src/tools/clangrefactoringbackend/source/clangtool.h b/src/tools/clangrefactoringbackend/source/clangtool.h index 2cc38eef0e2..9f0676a3975 100644 --- a/src/tools/clangrefactoringbackend/source/clangtool.h +++ b/src/tools/clangrefactoringbackend/source/clangtool.h @@ -84,6 +84,9 @@ public: template void addFiles(const Container &filePaths, const Utils::SmallStringVector &arguments); + void addFiles(const FilePaths &filePaths, + const Utils::SmallStringVector &arguments); + void addUnsavedFiles(const V2::FileContainers &unsavedFiles); diff --git a/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h b/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h index 4d83698a5db..d72691a70a7 100644 --- a/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h +++ b/src/tools/clangrefactoringbackend/source/collectmacrospreprocessorcallbacks.h @@ -25,7 +25,11 @@ #pragma once +#include "symbolsvisitorbase.h" #include "sourcelocationsutils.h" +#include "sourcelocationentry.h" +#include "symbolentry.h" +#include "useddefines.h" #include #include @@ -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 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; }; diff --git a/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.cpp b/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.cpp index 286fb5c4ba8..ad147a94cfd 100644 --- a/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.cpp +++ b/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.cpp @@ -33,8 +33,12 @@ namespace ClangBackEnd { bool CollectMacrosSourceFileCallbacks::handleBeginSource(clang::CompilerInstance &compilerInstance) { - auto callbacks = std::make_unique(m_sourceFiles, - m_filePathCache); + auto callbacks = std::make_unique(m_symbolEntries, + m_sourceLocationEntries, + m_sourceFiles, + m_usedDefines, + m_filePathCache, + compilerInstance.getSourceManager()); compilerInstance.getPreprocessorPtr()->addPPCallbacks(std::move(callbacks)); diff --git a/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.h b/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.h index 8f25fc0d55c..96429696d5d 100644 --- a/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.h +++ b/src/tools/clangrefactoringbackend/source/collectmacrossourcefilecallbacks.h @@ -25,6 +25,10 @@ #pragma once +#include "sourcelocationentry.h" +#include "symbolentry.h" +#include "useddefines.h" + #include #include @@ -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; }; diff --git a/src/tools/clangrefactoringbackend/source/collectsymbolsaction.h b/src/tools/clangrefactoringbackend/source/collectsymbolsaction.h index 01e4ed42d08..4ef8fb7b68f 100644 --- a/src/tools/clangrefactoringbackend/source/collectsymbolsaction.h +++ b/src/tools/clangrefactoringbackend/source/collectsymbolsaction.h @@ -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 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; }; diff --git a/src/tools/clangrefactoringbackend/source/collectsymbolsastvisitor.h b/src/tools/clangrefactoringbackend/source/collectsymbolsastvisitor.h index 07fe19bd0fc..3497a0502b7 100644 --- a/src/tools/clangrefactoringbackend/source/collectsymbolsastvisitor.h +++ b/src/tools/clangrefactoringbackend/source/collectsymbolsastvisitor.h @@ -25,32 +25,30 @@ #pragma once -#include "symbolentry.h" #include "sourcelocationentry.h" - -#include +#include "sourcelocationsutils.h" +#include "symbolentry.h" +#include "symbolsvisitorbase.h" #include #include #include -#include -#include #include namespace ClangBackEnd { -class CollectSymbolsASTVisitor : public clang::RecursiveASTVisitor +class CollectSymbolsASTVisitor : public clang::RecursiveASTVisitor, + 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()) { - m_symbolEntries.emplace(std::piecewise_construct, - std::forward_as_tuple(globalId), - std::forward_as_tuple(generateUSR(declaration), symbolName(declaration))); + Utils::optional usr = generateUSR(declaration); + if (usr) { + m_symbolEntries.emplace(std::piecewise_construct, + std::forward_as_tuple(globalId), + 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 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(pointer)); + return declaration->getName(); } private: SymbolEntries &m_symbolEntries; std::unordered_map m_filePathIndices; SourceLocationEntries &m_sourceLocationEntries; - FilePathCachingInterface &m_filePathCache; - const clang::SourceManager &m_sourceManager; }; diff --git a/src/tools/clangrefactoringbackend/source/projectpartentry.h b/src/tools/clangrefactoringbackend/source/projectpartentry.h new file mode 100644 index 00000000000..4cadaa4aa1e --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/projectpartentry.h @@ -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 + +#include + +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; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/sourcelocationentry.h b/src/tools/clangrefactoringbackend/source/sourcelocationentry.h index 1a7d89efcf9..03994233c07 100644 --- a/src/tools/clangrefactoringbackend/source/sourcelocationentry.h +++ b/src/tools/clangrefactoringbackend/source/sourcelocationentry.h @@ -27,6 +27,8 @@ #include +#include + #include #include @@ -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; } }; diff --git a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h index 5a103fd233e..85f99899e9e 100644 --- a/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h +++ b/src/tools/clangrefactoringbackend/source/storagesqlitestatementfactory.h @@ -57,7 +57,7 @@ public: table.addIndex({usrColumn, symbolNameColumn}); table.addIndex({symbolIdColumn}); - Sqlite::ImmediateTransaction 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 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 diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp index b8d1f1e90c6..0f5c57af0c3 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp @@ -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 &) diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.h b/src/tools/clangrefactoringbackend/source/symbolindexer.h index 239ffc9d5ee..f9e2f3fc3c0 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.h @@ -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 diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h index e09717b5d41..07478518579 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexing.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h @@ -75,7 +75,7 @@ private: StatementFactory m_statementFactory; Storage m_symbolStorage{m_statementFactory, m_filePathCache}; ClangPathWatcher 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 diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp index 94667298c85..dd16cdfd8e7 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp @@ -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 diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.h b/src/tools/clangrefactoringbackend/source/symbolscollector.h index 4cdf9ec4916..5347de13c47 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollector.h +++ b/src/tools/clangrefactoringbackend/source/symbolscollector.h @@ -29,7 +29,6 @@ #include "collectmacrossourcefilecallbacks.h" #include "collectsymbolsaction.h" #include "symbolscollectorinterface.h" -#include "symbolentry.h" #include @@ -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 diff --git a/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h b/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h index 688e348c569..b8438d57e0c 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h @@ -27,6 +27,7 @@ #include "symbolentry.h" #include "sourcelocationentry.h" +#include "useddefines.h" #include @@ -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 diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index 708bf96dfe8..bbdf11a9222 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -31,12 +31,14 @@ #include #include +#include +#include + namespace ClangBackEnd { template -class SymbolStorage : public SymbolStorageInterface +class SymbolStorage final : public SymbolStorageInterface { - using Transaction = Sqlite::ImmediateTransaction; 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(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); } } diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.cpp b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.cpp new file mode 100644 index 00000000000..dec03adc6a8 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.cpp @@ -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() +{ +} + +} diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h index 05d449748c2..8f05c512f7c 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h @@ -25,16 +25,28 @@ #pragma once +#include "projectpartentry.h" #include "sourcelocationentry.h" #include "symbolentry.h" +#include + 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 diff --git a/src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h b/src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h new file mode 100644 index 00000000000..9c5b701dfba --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolsvisitorbase.h @@ -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 + +#include +#include + +#include +#include +#include +#include + +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 generateUSR(const clang::Decl *declaration) + { + llvm::SmallVector usr; + + Utils::optional usrOptional; + + bool wasNotWorking = clang::index::generateUSRForDecl(declaration, usr); + + if (!wasNotWorking) + usrOptional.emplace(usr.data(), usr.size()); + + return usrOptional; + } + + Utils::optional generateUSR(clang::StringRef macroName, + clang::SourceLocation sourceLocation) + { + llvm::SmallVector usr; + + Utils::optional 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(pointer)); + } + +protected: + std::unordered_map m_filePathIndices; + FilePathCachingInterface &m_filePathCache; + const clang::SourceManager &m_sourceManager; +}; + +} // namespace ClangBackend diff --git a/src/tools/clangrefactoringbackend/source/useddefines.h b/src/tools/clangrefactoringbackend/source/useddefines.h new file mode 100644 index 00000000000..99548e8aa8b --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/useddefines.h @@ -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 + +#include + +#include + +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; + +} // ClangBackEnd diff --git a/tests/unit/unittest/data/symbolscollector_defines.h b/tests/unit/unittest/data/symbolscollector_defines.h new file mode 100644 index 00000000000..91ee38cdf98 --- /dev/null +++ b/tests/unit/unittest/data/symbolscollector_defines.h @@ -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 diff --git a/tests/unit/unittest/filepathstorage-test.cpp b/tests/unit/unittest/filepathstorage-test.cpp index 11711583ed2..b6373c3c6fc 100644 --- a/tests/unit/unittest/filepathstorage-test.cpp +++ b/tests/unit/unittest/filepathstorage-test.cpp @@ -48,8 +48,7 @@ protected: void SetUp(); protected: - NiceMock mockMutex; - NiceMock mockDatabase{mockMutex}; + NiceMock 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("/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("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())).Times(0); storage.fetchDirectoryId("/path/to"); } TEST_F(FilePathStorage, CallNotWriteForFetchingSoureIdForKnownEntry) { - EXPECT_CALL(insertIntoSources, write(_, _)).Times(0); + EXPECT_CALL(insertIntoSources, write(An(), An())).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("/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("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("/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("/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("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("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("file.cpp"))); - EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(_)) .Times(AnyNumber()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(_, _)) .Times(AnyNumber()); - EXPECT_CALL(insertIntoDirectories,write(_)) + EXPECT_CALL(insertIntoDirectories, write(An())) .Times(AnyNumber()); - EXPECT_CALL(insertIntoSources,write(_, _)) + EXPECT_CALL(insertIntoSources, write(An(), _)) .Times(AnyNumber()); EXPECT_CALL(selectAllDirectories, valuesReturnStdVectorDirectory(_)) .Times(AnyNumber()); diff --git a/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp b/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp index 79ee210a077..51e3ae67199 100644 --- a/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp +++ b/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp @@ -41,8 +41,7 @@ using StatementFactory = ClangBackEnd::FilePathStorageSqliteStatementFactory mockMutex; - NiceMock mockDatabase{mockMutex}; + NiceMock mockDatabase; StatementFactory factory{mockDatabase}; }; diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h index 4627e04427d..321cd1b540b 100644 --- a/tests/unit/unittest/google-using-declarations.h +++ b/tests/unit/unittest/google-using-declarations.h @@ -28,7 +28,9 @@ #include 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; diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index f06b6c943b0..db04845496d 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include @@ -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; } diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 73848ba8541..4afe5963f92 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -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; diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h index ce903c5b626..271fd77ae0a 100644 --- a/tests/unit/unittest/mocksqlitedatabase.h +++ b/tests/unit/unittest/mocksqlitedatabase.h @@ -27,31 +27,23 @@ #include "googletest.h" -#include "mockmutex.h" +#include "mocksqlitetransactionbackend.h" #include +#include #include -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))); - } - MOCK_METHOD1(execute, void (Utils::SmallStringView sqlStatement)); - MOCK_METHOD0(databaseMutex, - MockMutex &()); - MOCK_CONST_METHOD0(lastInsertedRowId, int64_t ()); + + MOCK_CONST_METHOD1(setLastInsertedRowId, + void (int64_t)); }; diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp index 1848fea3b26..c1a93ad3d60 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ b/tests/unit/unittest/mocksqlitereadstatement.cpp @@ -65,6 +65,13 @@ MockSqliteReadStatement::value(const Utils::SmallStringView &text) return valueReturnInt32(text); } +template <> +Utils::optional +MockSqliteReadStatement::value(const Utils::PathString &text) +{ + return valueReturnInt32(text); +} + template <> Utils::optional MockSqliteReadStatement::value(const int &directoryId, const Utils::SmallStringView &text) diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index ccec595455b..0b3d9977829 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -129,6 +129,10 @@ template <> Utils::optional MockSqliteReadStatement::value(const Utils::SmallStringView&); +template <> +Utils::optional +MockSqliteReadStatement::value(const Utils::PathString&); + template <> Utils::optional MockSqliteReadStatement::value(const int&, const Utils::SmallStringView&); @@ -137,6 +141,8 @@ template <> Utils::optional MockSqliteReadStatement::value(const int&); + + template <> Utils::optional MockSqliteReadStatement::value(const int&); diff --git a/tests/unit/unittest/mocksqlitetransactionbackend.h b/tests/unit/unittest/mocksqlitetransactionbackend.h new file mode 100644 index 00000000000..c367404530e --- /dev/null +++ b/tests/unit/unittest/mocksqlitetransactionbackend.h @@ -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 + +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 ()); +}; diff --git a/tests/unit/unittest/mocksqlitewritestatement.h b/tests/unit/unittest/mocksqlitewritestatement.h index 159077c8060..6a6b6d35af5 100644 --- a/tests/unit/unittest/mocksqlitewritestatement.h +++ b/tests/unit/unittest/mocksqlitewritestatement.h @@ -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; }; diff --git a/tests/unit/unittest/mocksymbolscollector.h b/tests/unit/unittest/mocksymbolscollector.h index 2c332dc1a83..8ba86d0509f 100644 --- a/tests/unit/unittest/mocksymbolscollector.h +++ b/tests/unit/unittest/mocksymbolscollector.h @@ -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 &()); }; diff --git a/tests/unit/unittest/mocksymbolstorage.h b/tests/unit/unittest/mocksymbolstorage.h index 84bf012f8ae..36cdf49381d 100644 --- a/tests/unit/unittest/mocksymbolstorage.h +++ b/tests/unit/unittest/mocksymbolstorage.h @@ -27,6 +27,8 @@ #include "googletest.h" +#include "mocksqlitedatabase.h" + #include 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)); }; diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index b1812ddc368..a89f649bd27 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -26,13 +26,17 @@ #include "googletest.h" #include "fakeprocess.h" -#include "mockfilepathcaching.h" + #include "mockpchgeneratornotifier.h" #include "testenvironment.h" +#include +#include #include #include +#include + #include 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 filePathCache; + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; + ClangBackEnd::RefactoringDatabaseInitializer 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; @@ -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)); -} } diff --git a/tests/unit/unittest/pchmanagerclient-test.cpp b/tests/unit/unittest/pchmanagerclient-test.cpp index 53a544841d6..ccce8212f05 100644 --- a/tests/unit/unittest/pchmanagerclient-test.cpp +++ b/tests/unit/unittest/pchmanagerclient-test.cpp @@ -31,6 +31,8 @@ #include #include +#include +#include #include #include #include @@ -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 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()}}}; diff --git a/tests/unit/unittest/pchmanagerclientserverinprocess-test.cpp b/tests/unit/unittest/pchmanagerclientserverinprocess-test.cpp index ed2ced23111..87eefb02bb5 100644 --- a/tests/unit/unittest/pchmanagerclientserverinprocess-test.cpp +++ b/tests/unit/unittest/pchmanagerclientserverinprocess-test.cpp @@ -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}}; diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp index a01facb02cb..07b7f68b878 100644 --- a/tests/unit/unittest/pchmanagerserver-test.cpp +++ b/tests/unit/unittest/pchmanagerserver-test.cpp @@ -30,21 +30,14 @@ #include "mockpchcreator.h" #include "mockprojectparts.h" +#include #include #include +#include #include #include 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; NiceMock mockClangPathWatcher; NiceMock mockProjectParts; - + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; + ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; + ClangBackEnd::FilePathCaching filePathCache{database}; ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockPchCreator, mockProjectParts}; NiceMock mockPchManagerClient; SmallString projectPartId1 = "project1"; @@ -71,12 +70,12 @@ protected: std::vector 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 projectParts{projectPart1, projectPart2}; FileContainer generatedFile{{"/path/to/", "file"}, "content", {}}; ClangBackEnd::UpdatePchProjectPartsMessage updatePchProjectPartsMessage{Utils::clone(projectParts), diff --git a/tests/unit/unittest/projectparts-test.cpp b/tests/unit/unittest/projectparts-test.cpp index e8680dbcccc..000c3b41cc0 100644 --- a/tests/unit/unittest/projectparts-test.cpp +++ b/tests/unit/unittest/projectparts-test.cpp @@ -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) diff --git a/tests/unit/unittest/projectupdater-test.cpp b/tests/unit/unittest/projectupdater-test.cpp index 0589115901f..1664dc8fa81 100644 --- a/tests/unit/unittest/projectupdater-test.cpp +++ b/tests/unit/unittest/projectupdater-test.cpp @@ -31,14 +31,18 @@ #include +#include #include #include +#include #include #include #include #include +#include + 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 initializer{database}; + ClangBackEnd::FilePathCaching filePathCache{database}; ClangPchManager::PchManagerClient pchManagerClient; MockPchManagerNotifier mockPchManagerNotifier{pchManagerClient}; NiceMock 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()}; -} } diff --git a/tests/unit/unittest/refactoringclientserverinprocess-test.cpp b/tests/unit/unittest/refactoringclientserverinprocess-test.cpp index f1ce7a9f5f1..65b6b4be634 100644 --- a/tests/unit/unittest/refactoringclientserverinprocess-test.cpp +++ b/tests/unit/unittest/refactoringclientserverinprocess-test.cpp @@ -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}}; diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp index ab5691d4ec5..ddcc46cfb8b 100644 --- a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -38,8 +38,7 @@ using Sqlite::Table; class RefactoringDatabaseInitializer : public testing::Test { protected: - NiceMock mockMutex; - NiceMock mockDatabase{mockMutex}; + NiceMock 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}; } diff --git a/tests/unit/unittest/refactoringserver-test.cpp b/tests/unit/unittest/refactoringserver-test.cpp index 44fe87497b6..089f027bbd9 100644 --- a/tests/unit/unittest/refactoringserver-test.cpp +++ b/tests/unit/unittest/refactoringserver-test.cpp @@ -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; NiceMock 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();", {}}}; diff --git a/tests/unit/unittest/sqlitetransaction-test.cpp b/tests/unit/unittest/sqlitetransaction-test.cpp index 69f90a71221..dbcffd08238 100644 --- a/tests/unit/unittest/sqlitetransaction-test.cpp +++ b/tests/unit/unittest/sqlitetransaction-test.cpp @@ -25,89 +25,81 @@ #include "googletest.h" +#include "mocksqlitetransactionbackend.h" + #include #include namespace { -using DeferredTransaction = Sqlite::DeferredTransaction; -using ImmediateTransaction = Sqlite::ImmediateTransaction; -using ExclusiveTransaction = Sqlite::ExclusiveTransaction; +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}; } } diff --git a/tests/unit/unittest/storagesqlitestatementfactory-test.cpp b/tests/unit/unittest/storagesqlitestatementfactory-test.cpp index d118570ea97..7116aef222c 100644 --- a/tests/unit/unittest/storagesqlitestatementfactory-test.cpp +++ b/tests/unit/unittest/storagesqlitestatementfactory-test.cpp @@ -42,8 +42,7 @@ using Sqlite::Table; class StorageSqliteStatementFactory : public testing::Test { protected: - NiceMock mockMutex; - NiceMock mockDatabase{mockMutex}; + NiceMock 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 = ?)")); +} + +} diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index 934733ba02e..1e0d239094e 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -27,6 +27,8 @@ #include "mockclangpathwatcher.h" #include "mocksymbolscollector.h" #include "mocksymbolstorage.h" +#include "mockfilepathcaching.h" +#include "mocksqlitetransactionbackend.h" #include #include @@ -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; NiceMock mockCollector; NiceMock mockStorage; NiceMock mockPathWatcher; - ClangBackEnd::SymbolIndexer indexer{mockCollector, mockStorage, mockPathWatcher}; + NiceMock 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}; } } diff --git a/tests/unit/unittest/symbolindexing-test.cpp b/tests/unit/unittest/symbolindexing-test.cpp index b5e93e4d6c0..462e8542f7c 100644 --- a/tests/unit/unittest/symbolindexing-test.cpp +++ b/tests/unit/unittest/symbolindexing-test.cpp @@ -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}); -} + } diff --git a/tests/unit/unittest/symbolscollector-test.cpp b/tests/unit/unittest/symbolscollector-test.cpp index 4a98306d93f..b04464521ea 100644 --- a/tests/unit/unittest/symbolscollector-test.cpp +++ b/tests/unit/unittest/symbolscollector-test.cpp @@ -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"}); - return 0; + 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}))); +} + +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))); } } diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index 0f93e210a70..96a869e8fb6 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -55,13 +55,9 @@ using Storage = ClangBackEnd::SymbolStorage; class SymbolStorage : public testing::Test { -protected: - void SetUp(); - protected: MockFilePathCaching filePathCache; - NiceMock mockMutex; - NiceMock mockDatabase{mockMutex}; + NiceMock 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("project"), TypedEq("[\"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("project"), TypedEq("[\"foo\"]"))); + EXPECT_CALL(mockDatabase, lastInsertedRowId()); + EXPECT_CALL(updateProjectPart, write(TypedEq("[\"foo\"]"), TypedEq("project"))); + + storage.insertOrUpdateProjectPart("project", {"foo"}); +} + +TEST_F(SymbolStorage, UpdateProjectPartSources) +{ + InSequence sequence; + + EXPECT_CALL(getProjectPartId, valueReturnInt32(TypedEq("project"))).WillRepeatedly(Return(42)); + EXPECT_CALL(deleteAllProjectPartsSourcesWithProjectPartId, write(TypedEq(42))); + EXPECT_CALL(insertProjectPartSources, write(TypedEq(42), TypedEq(1))); + EXPECT_CALL(insertProjectPartSources, write(TypedEq(42), TypedEq(2))); + + storage.updateProjectPartSources("project", {{1, 1}, {1, 2}}); +} + + } diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index c0fcdff3bae..b886e219efd 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -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 \