diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index b77118bb983..558c86baebf 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -27,7 +27,10 @@ HEADERS += \ $$PWD/symbolindexertaskqueue.h \ $$PWD/symbolindexertaskscheduler.h \ $$PWD/symbolscollectormanagerinterface.h \ - $$PWD/symbolindexertaskqueueinterface.h + $$PWD/symbolindexertaskqueueinterface.h \ + $$PWD/symbolindexertaskschedulerinterface.h \ + $$PWD/symbolscollectormanager.h \ + $$PWD/symbolindexertask.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ @@ -75,4 +78,5 @@ SOURCES += \ $$PWD/filestatuscache.cpp \ $$PWD/projectpartqueue.cpp \ $$PWD/symbolindexertaskqueue.cpp \ - $$PWD/symbolindexertaskscheduler.cpp + $$PWD/symbolindexertaskscheduler.cpp \ + $$PWD/symbolscollectormanager.cpp diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp index 58450cdc4d8..cb47f87406a 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp @@ -25,15 +25,18 @@ #include "symbolindexer.h" +#include +#include + namespace ClangBackEnd { -SymbolIndexer::SymbolIndexer(SymbolsCollectorInterface &symbolsCollector, +SymbolIndexer::SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQueue, SymbolStorageInterface &symbolStorage, ClangPathWatcherInterface &pathWatcher, FilePathCachingInterface &filePathCache, FileStatusCache &fileStatusCache, Sqlite::TransactionInterface &transactionInterface) - : m_symbolsCollector(symbolsCollector), + : m_symbolIndexerTaskQueue(symbolIndexerTaskQueue), m_symbolStorage(symbolStorage), m_pathWatcher(pathWatcher), m_filePathCache(filePathCache), @@ -52,41 +55,60 @@ void SymbolIndexer::updateProjectParts(V2::ProjectPartContainers &&projectParts, void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart, const V2::FileContainers &generatedFiles) { - m_symbolsCollector.clear(); + Sqlite::ImmediateTransaction transaction{m_transactionInterface}; + const auto optionalArtefact = m_symbolStorage.fetchProjectPartArtefact(projectPart.projectPartId); + int projectPartId = m_symbolStorage.insertOrUpdateProjectPart(projectPart.projectPartId, + projectPart.arguments, + projectPart.compilerMacros, + projectPart.includeSearchPaths); + transaction.commit(); - const Utils::optional optionalArtefact = m_symbolStorage.fetchProjectPartArtefact( - projectPart.projectPartId); + if (optionalArtefact) + projectPartId = optionalArtefact->projectPartId; FilePathIds sourcePathIds = updatableFilePathIds(projectPart, optionalArtefact); - if (!sourcePathIds.empty()) { - m_symbolsCollector.addFiles(projectPart.sourcePathIds, - compilerArguments(projectPart, optionalArtefact)); + if (sourcePathIds.empty()) + return; - m_symbolsCollector.addUnsavedFiles(generatedFiles); + Utils::SmallStringVector arguments = compilerArguments(projectPart, optionalArtefact); - m_symbolsCollector.collectSymbols(); + std::vector symbolIndexerTask; + symbolIndexerTask.reserve(projectPart.sourcePathIds.size()); - Sqlite::ImmediateTransaction transaction{m_transactionInterface}; + for (FilePathId sourcePathId : projectPart.sourcePathIds) { + auto indexing = [projectPart, arguments, generatedFiles, sourcePathId] + (SymbolsCollectorInterface &symbolsCollector, + SymbolStorageInterface &symbolStorage, + Sqlite::TransactionInterface &transactionInterface) { + symbolsCollector.addFile(sourcePathId, arguments); - m_symbolStorage.addSymbolsAndSourceLocations(m_symbolsCollector.symbols(), - m_symbolsCollector.sourceLocations()); + symbolsCollector.addUnsavedFiles(generatedFiles); - m_symbolStorage.insertOrUpdateProjectPart(projectPart.projectPartId, - projectPart.arguments, - projectPart.compilerMacros, - projectPart.includeSearchPaths); - m_symbolStorage.updateProjectPartSources(projectPart.projectPartId, - m_symbolsCollector.sourceFiles()); + symbolsCollector.collectSymbols(); - m_symbolStorage.insertOrUpdateUsedMacros(m_symbolsCollector.usedMacros()); + Sqlite::ImmediateTransaction transaction{transactionInterface}; - m_symbolStorage.insertFileStatuses(m_symbolsCollector.fileStatuses()); + symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), + symbolsCollector.sourceLocations()); - m_symbolStorage.insertOrUpdateSourceDependencies(m_symbolsCollector.sourceDependencies()); + symbolStorage.updateProjectPartSources(projectPart.projectPartId, + symbolsCollector.sourceFiles()); - transaction.commit(); + symbolStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); + + symbolStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + + symbolStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies()); + + transaction.commit(); + }; + + symbolIndexerTask.emplace_back(sourcePathId, projectPartId, std::move(indexing)); } + + m_symbolIndexerTaskQueue.addOrUpdateTasks(std::move(symbolIndexerTask)); + m_symbolIndexerTaskQueue.processTasks(); } void SymbolIndexer::pathsWithIdsChanged(const Utils::SmallStringVector &) @@ -95,40 +117,57 @@ void SymbolIndexer::pathsWithIdsChanged(const Utils::SmallStringVector &) void SymbolIndexer::pathsChanged(const FilePathIds &filePathIds) { + std::vector symbolIndexerTask; + symbolIndexerTask.reserve(filePathIds.size()); + for (FilePathId filePathId : filePathIds) - updateChangedPath(filePathId); + updateChangedPath(filePathId, symbolIndexerTask); + + m_symbolIndexerTaskQueue.addOrUpdateTasks(std::move(symbolIndexerTask)); + m_symbolIndexerTaskQueue.processTasks(); } -void SymbolIndexer::updateChangedPath(FilePathId filePathId) +void SymbolIndexer::updateChangedPath(FilePathId filePathId, + std::vector &symbolIndexerTask) { - m_symbolsCollector.clear(); m_fileStatusCache.update(filePathId); + Sqlite::DeferredTransaction transaction{m_transactionInterface}; const Utils::optional optionalArtefact = m_symbolStorage.fetchProjectPartArtefact(filePathId); + transaction.commit(); if (optionalArtefact && !optionalArtefact.value().compilerArguments.empty()) { + const ProjectPartArtefact &artefact = optionalArtefact.value(); - m_symbolsCollector.addFiles({filePathId}, - compilerArguments(artefact.compilerArguments, artefact.projectPartId)); + Utils::SmallStringVector arguments = compilerArguments(artefact.compilerArguments, + artefact.projectPartId); - m_symbolsCollector.collectSymbols(); + auto indexing = [projectPartId=artefact.projectPartId, arguments, filePathId] + (SymbolsCollectorInterface &symbolsCollector, + SymbolStorageInterface &symbolStorage, + Sqlite::TransactionInterface &transactionInterface) { + symbolsCollector.addFile(filePathId, arguments); - Sqlite::ImmediateTransaction transaction{m_transactionInterface}; + symbolsCollector.collectSymbols(); - m_symbolStorage.addSymbolsAndSourceLocations(m_symbolsCollector.symbols(), - m_symbolsCollector.sourceLocations()); + Sqlite::ImmediateTransaction transaction{transactionInterface}; - m_symbolStorage.updateProjectPartSources(artefact.projectPartId, - m_symbolsCollector.sourceFiles()); + symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), + symbolsCollector.sourceLocations()); - m_symbolStorage.insertOrUpdateUsedMacros(m_symbolsCollector.usedMacros()); + symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles()); - m_symbolStorage.insertFileStatuses(m_symbolsCollector.fileStatuses()); + symbolStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_symbolStorage.insertOrUpdateSourceDependencies(m_symbolsCollector.sourceDependencies()); + symbolStorage.insertFileStatuses(symbolsCollector.fileStatuses()); - transaction.commit(); + symbolStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies()); + + transaction.commit(); + }; + + symbolIndexerTask.emplace_back(filePathId, optionalArtefact->projectPartId, std::move(indexing)); } } diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.h b/src/tools/clangrefactoringbackend/source/symbolindexer.h index 4fc66fee0ff..ffa2269e9b3 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.h @@ -26,7 +26,7 @@ #pragma once #include "filestatuscache.h" -#include "symbolscollectorinterface.h" +#include "symbolindexertaskqueueinterface.h" #include "symbolstorageinterface.h" #include "clangpathwatcher.h" @@ -35,10 +35,12 @@ namespace ClangBackEnd { +class SymbolsCollectorInterface; + class SymbolIndexer : public ClangPathWatcherNotifier { public: - SymbolIndexer(SymbolsCollectorInterface &symbolsCollector, + SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQueue, SymbolStorageInterface &symbolStorage, ClangPathWatcherInterface &pathWatcher, FilePathCachingInterface &filePathCache, @@ -52,7 +54,8 @@ public: void pathsWithIdsChanged(const Utils::SmallStringVector &ids) override; void pathsChanged(const FilePathIds &filePathIds) override; - void updateChangedPath(FilePathId filePath); + void updateChangedPath(FilePathId filePath, + std::vector &symbolIndexerTask); bool compilerMacrosOrIncludeSearchPathsAreDifferent( const V2::ProjectPartContainer &projectPart, @@ -70,7 +73,7 @@ public: int projectPartId) const; private: - SymbolsCollectorInterface &m_symbolsCollector; + SymbolIndexerTaskQueueInterface &m_symbolIndexerTaskQueue; SymbolStorageInterface &m_symbolStorage; ClangPathWatcherInterface &m_pathWatcher; FilePathCachingInterface &m_filePathCache; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertask.h b/src/tools/clangrefactoringbackend/source/symbolindexertask.h new file mode 100644 index 00000000000..3b18681e072 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolindexertask.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** 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 + +#include + +namespace Sqlite { +class TransactionInterface; +} + +namespace ClangBackEnd { + +class SymbolIndexerTaskSchedulerInterface; +class SymbolsCollectorInterface; +class SymbolStorageInterface; + +class SymbolIndexerTask +{ +public: + using Callable = std::function; + + SymbolIndexerTask(FilePathId filePathId, + int projectPartId, + Callable &&callable) + : callable(std::move(callable)), + filePathId(filePathId), + projectPartId(projectPartId) + { + } + + SymbolIndexerTask clone() const + { + return *this; + } + + friend + bool operator==(const SymbolIndexerTask &first, const SymbolIndexerTask &second) + { + return first.filePathId == second.filePathId && first.projectPartId == second.projectPartId; + } + + friend + bool operator<(const SymbolIndexerTask &first, const SymbolIndexerTask &second) + { + return std::tie(first.filePathId, first.projectPartId) + < std::tie(second.filePathId, second.projectPartId); + } + + operator Callable&&() + { + return std::move(callable); + } + +public: + Callable callable; + FilePathId filePathId; + int projectPartId; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp index aa4fd382157..4bfed1fe31f 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp @@ -25,6 +25,8 @@ #include "symbolindexertaskqueue.h" +#include + namespace ClangBackEnd { namespace { @@ -60,11 +62,6 @@ OutputIt set_union_merge(InputIt1 first1, } -SymbolIndexerTaskQueue::SymbolIndexerTaskQueue() -{ - -} - void SymbolIndexerTaskQueue::addOrUpdateTasks(std::vector &&tasks) { std::vector mergedTasks; @@ -133,7 +130,12 @@ std::vector SymbolIndexerTaskQueue::projectPartNumberIds(const Util void SymbolIndexerTaskQueue::processTasks() { + int taskCount = m_symbolIndexerScheduler.freeSlots(); + auto newEnd = std::prev(m_tasks.end(), std::min(taskCount, int(m_tasks.size()))); + m_symbolIndexerScheduler.addTasks({std::make_move_iterator(newEnd), + std::make_move_iterator(m_tasks.end())}); + m_tasks.erase(newEnd, m_tasks.end()); } } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h index a4fb44de0ac..979129eb998 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h @@ -26,6 +26,7 @@ #pragma once #include "symbolindexertaskqueueinterface.h" +#include "symbolindexertask.h" #include @@ -34,59 +35,25 @@ #include #include +namespace Sqlite { +class TransactionInterface; +} + namespace ClangBackEnd { +class SymbolIndexerTaskSchedulerInterface; class SymbolsCollectorInterface; class SymbolStorageInterface; -class SymbolIndexerTask +class SymbolIndexerTaskQueue final : public SymbolIndexerTaskQueueInterface { public: - using Callable = std::function; + SymbolIndexerTaskQueue(SymbolIndexerTaskSchedulerInterface &symbolIndexerTaskScheduler) + : m_symbolIndexerScheduler(symbolIndexerTaskScheduler) + {} - SymbolIndexerTask(FilePathId filePathId, - std::size_t projectPartId, - Callable &&callable) - : callable(std::move(callable)), - filePathId(filePathId), - projectPartId(projectPartId) - { - } - - SymbolIndexerTask clone() const - { - return *this; - } - - friend - bool operator==(const SymbolIndexerTask &first, const SymbolIndexerTask &second) - { - return first.filePathId == second.filePathId && first.projectPartId == second.projectPartId; - } - - friend - bool operator<(const SymbolIndexerTask &first, const SymbolIndexerTask &second) - { - return std::tie(first.filePathId, first.projectPartId) - < std::tie(second.filePathId, second.projectPartId); - } - -public: - Callable callable; - FilePathId filePathId; - std::size_t projectPartId; -}; - -class SymbolIndexerTaskQueue -{ -public: - SymbolIndexerTaskQueue(); - - void addOrUpdateTasks(std::vector &&tasks) - /* [[expects: std::is_sorted(tasks)]] */; - void removeTasks(const Utils::SmallStringVector &projectPartIds) - /* [[expects: std::is_sorted(projectPartIds)]] */; + void addOrUpdateTasks(std::vector &&tasks); + void removeTasks(const Utils::SmallStringVector &projectPartIds); const std::vector &tasks() const; @@ -94,11 +61,13 @@ public: std::vector projectPartNumberIds(const Utils::SmallStringVector &projectPartIds) /* [[ensures result: std::is_sorted(result)]] */; - void processTasks() ; + void processTasks(); + void syncTasks(); private: std::vector m_projectPartIds; std::vector m_tasks; + SymbolIndexerTaskSchedulerInterface &m_symbolIndexerScheduler; }; } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h index 09b760d0a32..d4d79ec6cfb 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h @@ -25,11 +25,23 @@ #pragma once +#include + namespace ClangBackEnd { +class SymbolIndexerTask; + class SymbolIndexerTaskQueueInterface { public: + SymbolIndexerTaskQueueInterface() = default; + SymbolIndexerTaskQueueInterface(const SymbolIndexerTaskQueueInterface &) = delete; + SymbolIndexerTaskQueueInterface &operator=(const SymbolIndexerTaskQueueInterface &) = delete; + + virtual void addOrUpdateTasks(std::vector &&tasks) = 0 + /* [[expects: std::is_sorted(tasks)]] */; + virtual void removeTasks(const Utils::SmallStringVector &projectPartIds) = 0 + /* [[expects: std::is_sorted(projectPartIds)]] */; virtual void processTasks() = 0; protected: diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp index bd065311055..e9f5cbe285b 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp @@ -87,7 +87,7 @@ void SymbolIndexerTaskScheduler::addTasks(std::vector &&tasks) auto callWrapper = [&, task=std::move(task)] ( std::reference_wrapper symbolsCollector) -> SymbolsCollectorInterface& { - task(symbolsCollector.get(), m_symbolStorage); + task(symbolsCollector.get(), m_symbolStorage, m_transactionInterface); executeInLoop([&] { m_symbolIndexerTaskQueue.processTasks(); }); @@ -105,11 +105,14 @@ const std::vector &SymbolIndexerTaskSchedule return m_futures; } -int SymbolIndexerTaskScheduler::freeSlots() +uint SymbolIndexerTaskScheduler::freeSlots() { removeFinishedFutures(); - return std::max(m_hardware_concurrency - int(m_futures.size()), 0); + if (m_isDisabled) + return 0; + + return uint(std::max(int(m_hardware_concurrency) - int(m_futures.size()), 0)); } void SymbolIndexerTaskScheduler::syncTasks() @@ -118,6 +121,11 @@ void SymbolIndexerTaskScheduler::syncTasks() future.wait(); } +void SymbolIndexerTaskScheduler::disable() +{ + m_isDisabled = true; +} + void SymbolIndexerTaskScheduler::removeFinishedFutures() { auto notReady = [] (Future &future) { @@ -127,7 +135,9 @@ void SymbolIndexerTaskScheduler::removeFinishedFutures() auto split = std::partition(m_futures.begin(), m_futures.end(), notReady); std::for_each(split, m_futures.end(), [] (Future &future) { - future.get().setIsUsed(false); + SymbolsCollectorInterface &symbolCollector = future.get(); + symbolCollector.setIsUsed(false); + symbolCollector.clear(); }); m_futures.erase(split, m_futures.end()); diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h index 919b8c1fd7b..6182376dab0 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h @@ -25,10 +25,17 @@ #pragma once +#include "symbolindexertaskschedulerinterface.h" +#include "symbolindexertask.h" + #include #include #include +namespace Sqlite { +class TransactionInterface; +}; + namespace ClangBackEnd { class FilePathCachingInterface; @@ -37,20 +44,21 @@ class SymbolsCollectorManagerInterface; class SymbolIndexerTaskQueueInterface; class SymbolStorageInterface; -class SymbolIndexerTaskScheduler +class SymbolIndexerTaskScheduler final : public SymbolIndexerTaskSchedulerInterface { public: - using Task = std::function; + using Task = SymbolIndexerTask::Callable; using Future = std::future; SymbolIndexerTaskScheduler(SymbolsCollectorManagerInterface &symbolsCollectorManager, SymbolStorageInterface &symbolStorage, + Sqlite::TransactionInterface &transactionInterface, SymbolIndexerTaskQueueInterface &symbolIndexerTaskQueue, - int hardware_concurrency, + uint hardware_concurrency, std::launch launchPolicy = std::launch::async) : m_symbolsCollectorManager(symbolsCollectorManager), m_symbolStorage(symbolStorage), + m_transactionInterface(transactionInterface), m_symbolIndexerTaskQueue(symbolIndexerTaskQueue), m_hardware_concurrency(hardware_concurrency), m_launchPolicy(launchPolicy) @@ -60,10 +68,12 @@ public: const std::vector &futures() const; - int freeSlots(); + uint freeSlots(); void syncTasks(); + void disable(); + private: void removeFinishedFutures(); @@ -71,9 +81,11 @@ private: std::vector m_futures; SymbolsCollectorManagerInterface &m_symbolsCollectorManager; SymbolStorageInterface &m_symbolStorage; + Sqlite::TransactionInterface &m_transactionInterface; SymbolIndexerTaskQueueInterface &m_symbolIndexerTaskQueue; - int m_hardware_concurrency; + uint m_hardware_concurrency; std::launch m_launchPolicy; + bool m_isDisabled = false; }; } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskschedulerinterface.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskschedulerinterface.h new file mode 100644 index 00000000000..c71454df3d8 --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskschedulerinterface.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** 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 +#include + +namespace Sqlite { +class TransactionInterface; +} + +namespace ClangBackEnd { + +class SymbolsCollectorInterface; +class SymbolStorageInterface; + +using uint = unsigned int; + +class SymbolIndexerTaskSchedulerInterface +{ +public: + using Task = std::function; + + SymbolIndexerTaskSchedulerInterface() = default; + SymbolIndexerTaskSchedulerInterface(const SymbolIndexerTaskSchedulerInterface &) = delete; + SymbolIndexerTaskSchedulerInterface &operator=(const SymbolIndexerTaskSchedulerInterface &) = delete; + + virtual void addTasks(std::vector &&tasks) = 0; + virtual uint freeSlots() = 0; + +protected: + ~SymbolIndexerTaskSchedulerInterface() = default; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h index 96f6ecb1e5a..07188690c7f 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexing.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h @@ -30,6 +30,9 @@ #include "storagesqlitestatementfactory.h" #include "symbolindexer.h" #include "symbolscollector.h" +#include "symbolscollectormanager.h" +#include "symbolindexertaskqueue.h" +#include "symbolindexertaskscheduler.h" #include "symbolstorage.h" #include @@ -41,6 +44,8 @@ #include +#include + namespace ClangBackEnd { class SymbolIndexing final : public SymbolIndexingInterface @@ -52,26 +57,44 @@ public: SymbolIndexing(Sqlite::Database &database, FilePathCachingInterface &filePathCache) : m_filePathCache(filePathCache), - m_statementFactory(database) + m_statementFactory(database), + m_collectorManger(database), + m_indexerScheduler(m_collectorManger, m_symbolStorage, database, m_indexerQueue, std::thread::hardware_concurrency()) { } + ~SymbolIndexing() + { + syncTasks(); + } + SymbolIndexer &indexer() { return m_indexer; } + void syncTasks() + { + m_indexerScheduler.disable(); + while (!m_indexerScheduler.futures().empty()) { + m_indexerScheduler.syncTasks(); + m_indexerScheduler.freeSlots(); + } + } + void updateProjectParts(V2::ProjectPartContainers &&projectParts, const V2::FileContainers &generatedFiles) override; private: FilePathCachingInterface &m_filePathCache; - SymbolsCollector m_collector{m_filePathCache}; StatementFactory m_statementFactory; Storage m_symbolStorage{m_statementFactory}; ClangPathWatcher m_sourceWatcher{m_filePathCache}; FileStatusCache m_fileStatusCache{m_filePathCache}; - SymbolIndexer m_indexer{m_collector, + SymbolsCollectorManager m_collectorManger; + SymbolIndexerTaskScheduler m_indexerScheduler; + SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler}; + SymbolIndexer m_indexer{m_indexerQueue, m_symbolStorage, m_sourceWatcher, m_filePathCache, diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp index 490c0745fa2..57815da0acb 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp @@ -29,11 +29,11 @@ namespace ClangBackEnd { -SymbolsCollector::SymbolsCollector(FilePathCachingInterface &filePathCache) - : m_indexDataConsumer(std::make_shared(m_symbolEntries, m_sourceLocationEntries, filePathCache, m_sourcesManager)), +SymbolsCollector::SymbolsCollector(Sqlite::Database &database) + : m_filePathCache(database), + m_indexDataConsumer(std::make_shared(m_symbolEntries, m_sourceLocationEntries, m_filePathCache, m_sourcesManager)), m_collectSymbolsAction(m_indexDataConsumer), - m_collectMacrosSourceFileCallbacks(m_symbolEntries, m_sourceLocationEntries, filePathCache, m_sourcesManager), - m_filePathCache(filePathCache) + m_collectMacrosSourceFileCallbacks(m_symbolEntries, m_sourceLocationEntries, m_filePathCache, m_sourcesManager) { } @@ -44,6 +44,11 @@ void SymbolsCollector::addFiles(const FilePathIds &filePathIds, m_collectMacrosSourceFileCallbacks.addSourceFiles(filePathIds); } +void SymbolsCollector::addFile(FilePathId filePathId, const Utils::SmallStringVector &arguments) +{ + addFiles({filePathId}, arguments); +} + void SymbolsCollector::addUnsavedFiles(const V2::FileContainers &unsavedFiles) { m_clangTool.addUnsavedFiles(unsavedFiles); diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.h b/src/tools/clangrefactoringbackend/source/symbolscollector.h index d14fef53fe4..1b6c4948959 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollector.h +++ b/src/tools/clangrefactoringbackend/source/symbolscollector.h @@ -31,17 +31,22 @@ #include "sourcesmanager.h" #include "symbolscollectorinterface.h" -#include +#include + +namespace Sqlite { +class Database; +} namespace ClangBackEnd { class SymbolsCollector final : public SymbolsCollectorInterface { public: - SymbolsCollector(FilePathCachingInterface &filePathCache); + SymbolsCollector(Sqlite::Database &database); void addFiles(const FilePathIds &filePathIds, - const Utils::SmallStringVector &arguments) override; + const Utils::SmallStringVector &arguments); + void addFile(FilePathId filePathId, const Utils::SmallStringVector &arguments) override; void addUnsavedFiles(const V2::FileContainers &unsavedFiles) override; @@ -60,6 +65,7 @@ public: void setIsUsed(bool isUsed) override; private: + FilePathCaching m_filePathCache; ClangTool m_clangTool; SymbolEntries m_symbolEntries; SourceLocationEntries m_sourceLocationEntries; @@ -67,7 +73,6 @@ private: CollectSymbolsAction m_collectSymbolsAction; CollectMacrosSourceFileCallbacks m_collectMacrosSourceFileCallbacks; SourcesManager m_sourcesManager; - FilePathCachingInterface &m_filePathCache; bool m_isUsed = false; }; diff --git a/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h b/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h index 715e26be1cc..2bf344d4b11 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h @@ -44,11 +44,11 @@ class SymbolsCollectorInterface { public: SymbolsCollectorInterface() = default; + virtual ~SymbolsCollectorInterface() = default; SymbolsCollectorInterface(const SymbolsCollectorInterface &) = delete; SymbolsCollectorInterface &operator=(const SymbolsCollectorInterface &) = delete; - virtual void addFiles(const FilePathIds &filePathIds, - const Utils::SmallStringVector &arguments) = 0; + virtual void addFile(FilePathId filePathId, const Utils::SmallStringVector &arguments) = 0; virtual void addUnsavedFiles(const V2::FileContainers &unsavedFiles) = 0; @@ -65,9 +65,6 @@ public: virtual bool isUsed() const = 0; virtual void setIsUsed(bool isUsed) = 0; - -protected: - ~SymbolsCollectorInterface() = default; }; } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolscollectormanager.cpp b/src/tools/clangrefactoringbackend/source/symbolscollectormanager.cpp new file mode 100644 index 00000000000..c6cc5e283eb --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolscollectormanager.cpp @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** 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 "symbolscollectormanager.h" + +#include "symbolscollector.h" + +namespace ClangBackEnd { + + + + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolscollectormanager.h b/src/tools/clangrefactoringbackend/source/symbolscollectormanager.h new file mode 100644 index 00000000000..5443911640d --- /dev/null +++ b/src/tools/clangrefactoringbackend/source/symbolscollectormanager.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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 "symbolscollectormanagerinterface.h" +#include "symbolscollectorinterface.h" + +#include + +namespace Sqlite { +class Database; +} + +namespace ClangBackEnd { + +class SymbolsCollector; +template +class SymbolsCollectorManager final : public SymbolsCollectorManagerInterface +{ +public: + SymbolsCollectorManager(Sqlite::Database &database) + : m_database(database) + {} + + SymbolsCollector &unusedSymbolsCollector() override + { + auto split = std::partition(m_collectors.begin(), + m_collectors.end(), + [] (const auto &collector) { + return collector->isUsed(); + }); + + auto freeCollectors = std::distance(split, m_collectors.end()); + + if (freeCollectors > 0) + return usedCollector(*split->get()); + + m_collectors.emplace_back(std::make_unique(m_database)); + + return usedCollector(*m_collectors.back().get()); + } + + const std::vector> &collectors() const + { + return m_collectors; + } + +private: + SymbolsCollector &usedCollector(SymbolsCollector &collector) + { + collector.setIsUsed(true); + return collector; + } + +private: + std::vector> m_collectors; + Sqlite::Database &m_database; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolscollectormanagerinterface.h b/src/tools/clangrefactoringbackend/source/symbolscollectormanagerinterface.h index 82a169ff0c3..12a96990701 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollectormanagerinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolscollectormanagerinterface.h @@ -34,6 +34,10 @@ class SymbolsCollectorInterface; class SymbolsCollectorManagerInterface { public: + SymbolsCollectorManagerInterface() = default; + SymbolsCollectorManagerInterface(const SymbolsCollectorManagerInterface &) = delete; + SymbolsCollectorManagerInterface &operator=(const SymbolsCollectorManagerInterface &) = delete; + virtual SymbolsCollectorInterface &unusedSymbolsCollector() = 0; protected: diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index 9a474d4e85a..abea7854ae5 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -64,7 +64,7 @@ public: deleteNewLocationsTable(); } - void insertOrUpdateProjectPart(Utils::SmallStringView projectPartName, + int insertOrUpdateProjectPart(Utils::SmallStringView projectPartName, const Utils::SmallStringVector &commandLineArguments, const CompilerMacros &compilerMacros, const Utils::SmallStringVector &includeSearchPaths) override @@ -88,6 +88,8 @@ public: includeSearchPathsAsJason, projectPartName); } + + return int(m_statementFactory.database.lastInsertedRowId()); } Utils::optional fetchProjectPartArtefact(FilePathId sourceId) const override diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h index 70f5901447d..ffd85103c20 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h @@ -49,10 +49,10 @@ public: virtual void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries, const SourceLocationEntries &sourceLocations) = 0; - virtual void insertOrUpdateProjectPart(Utils::SmallStringView projectPartName, - const Utils::SmallStringVector &commandLineArguments, - const CompilerMacros &compilerMacros, - const Utils::SmallStringVector &includeSearchPaths) = 0; + virtual int insertOrUpdateProjectPart(Utils::SmallStringView projectPartName, + const Utils::SmallStringVector &commandLineArguments, + const CompilerMacros &compilerMacros, + const Utils::SmallStringVector &includeSearchPaths) = 0; virtual void updateProjectPartSources(Utils::SmallStringView projectPartName, const FilePathIds &sourceFilePathIds) = 0; virtual void updateProjectPartSources(int projectPartId, diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h index 321cd1b540b..e7fe88065b6 100644 --- a/tests/unit/unittest/google-using-declarations.h +++ b/tests/unit/unittest/google-using-declarations.h @@ -39,6 +39,7 @@ using testing::ElementsAre; using testing::Field; using testing::HasSubstr; using testing::InSequence; +using testing::Invoke; using testing::IsEmpty; using testing::Matcher; using testing::Mock; diff --git a/tests/unit/unittest/mocksymbolindexertaskqueue.h b/tests/unit/unittest/mocksymbolindexertaskqueue.h index 1eca733ade4..276dcf2c480 100644 --- a/tests/unit/unittest/mocksymbolindexertaskqueue.h +++ b/tests/unit/unittest/mocksymbolindexertaskqueue.h @@ -32,5 +32,9 @@ class MockSymbolIndexerTaskQueue : public ClangBackEnd::SymbolIndexerTaskQueueInterface { public: + MOCK_METHOD1(addOrUpdateTasks, + void (std::vector< ClangBackEnd::SymbolIndexerTask> &&tasks)); + MOCK_METHOD1(removeTasks, + void (const Utils::SmallStringVector &projectPartIds)); MOCK_METHOD0(processTasks, void()); }; diff --git a/tests/unit/unittest/mocksymbolindexertaskscheduler.h b/tests/unit/unittest/mocksymbolindexertaskscheduler.h new file mode 100644 index 00000000000..c3b70ca93c9 --- /dev/null +++ b/tests/unit/unittest/mocksymbolindexertaskscheduler.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** 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 MockSymbolIndexerTaskScheduler : public ClangBackEnd::SymbolIndexerTaskSchedulerInterface +{ +public: + MOCK_METHOD1(addTasks, + void (const std::vector &)); + MOCK_METHOD0(freeSlots, + uint ()); + + void addTasks(std::vector &&tasks) override + { + addTasks(tasks); + } +}; diff --git a/tests/unit/unittest/mocksymbolscollector.h b/tests/unit/unittest/mocksymbolscollector.h index 1eb5eb03cb6..bf82f538ae1 100644 --- a/tests/unit/unittest/mocksymbolscollector.h +++ b/tests/unit/unittest/mocksymbolscollector.h @@ -29,14 +29,28 @@ #include +namespace Sqlite { +class Database; +} + class MockSymbolsCollector : public ClangBackEnd::SymbolsCollectorInterface { public: + MockSymbolsCollector() + { + } + + MockSymbolsCollector(const Sqlite::Database &) + { + ON_CALL(*this, setIsUsed(_)).WillByDefault(Invoke(this, &MockSymbolsCollector::setIsUsed2)); + ON_CALL(*this, isUsed()).WillByDefault(Invoke(this, &MockSymbolsCollector::isUsed2)); + } + MOCK_METHOD0(collectSymbols, void()); - MOCK_METHOD2(addFiles, - void(const ClangBackEnd::FilePathIds &filePathIds, + MOCK_METHOD2(addFile, + void(ClangBackEnd::FilePathId filePathId, const Utils::SmallStringVector &arguments)); MOCK_METHOD1(addUnsavedFiles, @@ -60,12 +74,25 @@ public: MOCK_CONST_METHOD0(fileStatuses, const ClangBackEnd::FileStatuses &()); - MOCK_CONST_METHOD0(sourceDependencies, - const ClangBackEnd::SourceDependencies &()); + MOCK_CONST_METHOD0(sourceDependencies, + const ClangBackEnd::SourceDependencies &()); - MOCK_CONST_METHOD0(isUsed, - bool()); + MOCK_CONST_METHOD0(isUsed, + bool()); - MOCK_METHOD1(setIsUsed, - void(bool)); + MOCK_METHOD1(setIsUsed, + void(bool)); + + void setIsUsed2(bool isUsed) + { + used = isUsed; + } + + bool isUsed2() const + { + return used; + } + +public: + bool used = false; }; diff --git a/tests/unit/unittest/mocksymbolstorage.h b/tests/unit/unittest/mocksymbolstorage.h index 90142fe9ee1..ca5f06a1501 100644 --- a/tests/unit/unittest/mocksymbolstorage.h +++ b/tests/unit/unittest/mocksymbolstorage.h @@ -38,10 +38,10 @@ public: void(const ClangBackEnd::SymbolEntries &symbolEentries, const ClangBackEnd::SourceLocationEntries &sourceLocations)); MOCK_METHOD4(insertOrUpdateProjectPart, - void(Utils::SmallStringView projectPartName, - const Utils::SmallStringVector &commandLineArgument, - const ClangBackEnd::CompilerMacros &compilerMacros, - const Utils::SmallStringVector &includeSearchPaths)); + int(Utils::SmallStringView projectPartName, + const Utils::SmallStringVector &commandLineArgument, + const ClangBackEnd::CompilerMacros &compilerMacros, + const Utils::SmallStringVector &includeSearchPaths)); MOCK_METHOD2(updateProjectPartSources, void(Utils::SmallStringView projectPartName, const ClangBackEnd::FilePathIds &sourceFilePathIds)); diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index 08293a05877..8ce8e40c7a4 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -34,9 +34,13 @@ #include #include #include +#include #include +#include +#include #include +#include #include #include @@ -54,6 +58,10 @@ using ClangBackEnd::V2::ProjectPartContainers; using ClangBackEnd::V2::FileContainers; using ClangBackEnd::SymbolEntries; using ClangBackEnd::SymbolEntry; +using ClangBackEnd::SymbolIndexerTask; +using ClangBackEnd::SymbolIndexerTaskQueue; +using ClangBackEnd::SymbolIndexerTaskScheduler; +using ClangBackEnd::SymbolsCollectorManager; using ClangBackEnd::SourceDependencies; using ClangBackEnd::SourceLocationEntries; using ClangBackEnd::SourceLocationEntry; @@ -89,6 +97,21 @@ protected: ON_CALL(mockCollector, sourceDependencies()).WillByDefault(ReturnRef(sourceDependencies)); ON_CALL(mockStorage, fetchProjectPartArtefact(A())).WillByDefault(Return(artefact)); ON_CALL(mockStorage, fetchLowestLastModifiedTime(A())).WillByDefault(Return(QDateTime::currentSecsSinceEpoch())); + + mockCollector.setIsUsed(false); + } + + void TearDown() + { + syncTasks(); + } + + void syncTasks() + { + while (!indexerQueue.tasks().empty() || !indexerScheduler.futures().empty()) { + indexerScheduler.syncTasks(); + QCoreApplication::processEvents(); + } } static void SetUpTestCase() @@ -153,23 +176,26 @@ protected: ClangBackEnd::ProjectPartArtefact emptyArtefact{"", "", "", 74}; ClangBackEnd::ProjectPartPch projectPartPch{"/path/to/pch", 4}; NiceMock mockSqliteTransactionBackend; - NiceMock mockCollector; NiceMock mockStorage; NiceMock mockPathWatcher; ClangBackEnd::FileStatusCache fileStatusCache{filePathCache}; - ClangBackEnd::SymbolIndexer indexer{mockCollector, + SymbolsCollectorManager> collectorManger{data->database}; + SymbolIndexerTaskScheduler indexerScheduler{collectorManger, mockStorage, mockSqliteTransactionBackend, indexerQueue, 1}; + SymbolIndexerTaskQueue indexerQueue{indexerScheduler}; + ClangBackEnd::SymbolIndexer indexer{indexerQueue, mockStorage, mockPathWatcher, filePathCache, fileStatusCache, mockSqliteTransactionBackend}; + NiceMock &mockCollector{collectorManger.unusedSymbolsCollector()}; }; std::unique_ptr SymbolIndexer::data; TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector) { - EXPECT_CALL(mockCollector, addFiles(projectPart1.sourcePathIds, projectPart1.arguments)); + EXPECT_CALL(mockCollector, addFile(main1PathId, projectPart1.arguments)); indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved)); } @@ -179,14 +205,14 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithPrecompiledHeaderInColl ON_CALL(mockStorage, fetchProjectPartArtefact(TypedEq(projectPart1.projectPartId))).WillByDefault(Return(emptyArtefact)); ON_CALL(mockStorage, fetchPrecompiledHeader(Eq(artefact.projectPartId))).WillByDefault(Return(projectPartPch)); - EXPECT_CALL(mockCollector, addFiles(projectPart1.sourcePathIds, - ElementsAre(Eq("-I"), - Eq(TESTDATA_DIR), - Eq("-Wno-pragma-once-outside-header"), - Eq("-Xclang"), - Eq("-include-pch"), - Eq("-Xclang"), - Eq("/path/to/pch")))); + EXPECT_CALL(mockCollector, addFile(main1PathId, + ElementsAre(Eq("-I"), + Eq(TESTDATA_DIR), + Eq("-Wno-pragma-once-outside-header"), + Eq("-Xclang"), + Eq("-include-pch"), + Eq("-Xclang"), + Eq("/path/to/pch")))); indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved)); } @@ -195,10 +221,10 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithoutPrecompiledHeaderInC { ON_CALL(mockStorage, fetchProjectPartArtefact(TypedEq(projectPart1.projectPartId))).WillByDefault(Return(emptyArtefact)); - EXPECT_CALL(mockCollector, addFiles(projectPart1.sourcePathIds, - ElementsAre(Eq("-I"), - Eq(TESTDATA_DIR), - Eq("-Wno-pragma-once-outside-header")))); + EXPECT_CALL(mockCollector, addFile(main1PathId, + ElementsAre(Eq("-I"), + Eq(TESTDATA_DIR), + Eq("-Wno-pragma-once-outside-header")))); indexer.updateProjectParts({projectPart1}, Utils::clone(unsaved)); } @@ -212,14 +238,14 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsClearInCollector) TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollectorForEveryProjectPart) { - EXPECT_CALL(mockCollector, addFiles(_, _)).Times(2); + EXPECT_CALL(mockCollector, addFile(_, _)).Times(2); indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved)); } TEST_F(SymbolIndexer, UpdateProjectPartsDoesNotCallAddFilesInCollectorForEmptyEveryProjectParts) { - EXPECT_CALL(mockCollector, addFiles(_, _)) + EXPECT_CALL(mockCollector, addFile(_, _)) .Times(0); indexer.updateProjectParts({}, {}); @@ -255,9 +281,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddUnsavedFilesInCollector) TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddSymbolsAndSourceLocationsInStorage) { - EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(2); EXPECT_CALL(mockStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)).Times(2); - EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(2); indexer.updateProjectParts({projectPart1, projectPart2}, Utils::clone(unsaved)); } @@ -320,14 +344,15 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrder) { InSequence s; - EXPECT_CALL(mockCollector, clear()); + EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockStorage, fetchProjectPartArtefact(TypedEq(projectPart1.projectPartId))); - EXPECT_CALL(mockCollector, addFiles(_, _)); + EXPECT_CALL(mockStorage, insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), Eq(projectPart1.arguments), Eq(projectPart1.compilerMacros), Eq(projectPart1.includeSearchPaths))); + EXPECT_CALL(mockSqliteTransactionBackend, commit()); + EXPECT_CALL(mockCollector, addFile(main1PathId, projectPart1.arguments)); EXPECT_CALL(mockCollector, addUnsavedFiles(unsaved)); EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); - EXPECT_CALL(mockStorage, insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), Eq(projectPart1.arguments), Eq(projectPart1.compilerMacros), Eq(projectPart1.includeSearchPaths))); EXPECT_CALL(mockStorage, updateProjectPartSources(TypedEq(projectPart1.projectPartId), Eq(sourceFileIds))); EXPECT_CALL(mockStorage, insertOrUpdateUsedMacros(Eq(usedMacros))); EXPECT_CALL(mockStorage, insertFileStatuses(Eq(fileStatus))); @@ -341,7 +366,7 @@ TEST_F(SymbolIndexer, CallSetNotifier) { EXPECT_CALL(mockPathWatcher, setNotifier(_)); - ClangBackEnd::SymbolIndexer indexer{mockCollector, mockStorage, mockPathWatcher, filePathCache, fileStatusCache, mockSqliteTransactionBackend}; + ClangBackEnd::SymbolIndexer indexer{indexerQueue, mockStorage, mockPathWatcher, filePathCache, fileStatusCache, mockSqliteTransactionBackend}; } TEST_F(SymbolIndexer, PathChangedCallsFetchProjectPartArtefactInStorage) @@ -356,9 +381,10 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder) { InSequence s; - EXPECT_CALL(mockCollector, clear()); - EXPECT_CALL(mockStorage, fetchProjectPartArtefact(sourceFileIds[0])); - EXPECT_CALL(mockCollector, addFiles(ElementsAre(sourceFileIds[0]), Eq(artefact.compilerArguments))); + EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); + EXPECT_CALL(mockStorage, fetchProjectPartArtefact(sourceFileIds[0])).WillOnce(Return(artefact)); + EXPECT_CALL(mockSqliteTransactionBackend, commit()); + EXPECT_CALL(mockCollector, addFile(Eq(sourceFileIds[0]), Eq(artefact.compilerArguments))); EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); @@ -368,17 +394,17 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder) EXPECT_CALL(mockStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); - indexer.updateChangedPath(sourceFileIds[0]); + indexer.pathsChanged({sourceFileIds[0]}); } TEST_F(SymbolIndexer, HandleEmptyOptionalArtifactInUpdateChangedPath) { - ON_CALL(mockStorage, fetchProjectPartArtefact(TypedEq(sourceFileIds[0]))) - .WillByDefault(Return(emptyArtefact)); + InSequence s; - EXPECT_CALL(mockCollector, clear()); - EXPECT_CALL(mockStorage, fetchProjectPartArtefact(sourceFileIds[0])); - EXPECT_CALL(mockCollector, addFiles(_, _)).Times(0); + EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); + EXPECT_CALL(mockStorage, fetchProjectPartArtefact(sourceFileIds[0])).WillOnce(Return(emptyArtefact)); + EXPECT_CALL(mockSqliteTransactionBackend, commit()); + EXPECT_CALL(mockCollector, addFile(_, _)).Times(0); EXPECT_CALL(mockCollector, collectSymbols()).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockStorage, addSymbolsAndSourceLocations(_, _)).Times(0); @@ -388,7 +414,7 @@ TEST_F(SymbolIndexer, HandleEmptyOptionalArtifactInUpdateChangedPath) EXPECT_CALL(mockStorage, insertOrUpdateSourceDependencies(_)).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); - indexer.updateChangedPath(sourceFileIds[0]); + indexer.pathsChanged({sourceFileIds[0]}); } TEST_F(SymbolIndexer, UpdateChangedPathIsUsingPrecompiledHeader) @@ -397,26 +423,28 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsUsingPrecompiledHeader) .WillByDefault(Return(artefact)); ON_CALL(mockStorage, fetchPrecompiledHeader(Eq(artefact.projectPartId))) .WillByDefault(Return(projectPartPch)); + std::vector symbolIndexerTask; - EXPECT_CALL(mockCollector, addFiles(projectPart1.sourcePathIds, - ElementsAre(Eq("-DFOO"), - Eq("-Xclang"), - Eq("-include-pch"), - Eq("-Xclang"), - Eq("/path/to/pch")))); + EXPECT_CALL(mockCollector, addFile(Eq(sourceFileIds[0]), + ElementsAre(Eq("-DFOO"), + Eq("-Xclang"), + Eq("-include-pch"), + Eq("-Xclang"), + Eq("/path/to/pch")))); - indexer.updateChangedPath(sourceFileIds[0]); + indexer.pathsChanged({sourceFileIds[0]}); } TEST_F(SymbolIndexer, UpdateChangedPathIsNotUsingPrecompiledHeaderIfItNotExists) { ON_CALL(mockStorage, fetchProjectPartArtefact(TypedEq(sourceFileIds[0]))) .WillByDefault(Return(artefact)); + std::vector symbolIndexerTask; - EXPECT_CALL(mockCollector, addFiles(projectPart1.sourcePathIds, - ElementsAre(Eq("-DFOO")))); + EXPECT_CALL(mockCollector, addFile(Eq(sourceFileIds[0]), + ElementsAre(Eq("-DFOO")))); - indexer.updateChangedPath(sourceFileIds[0]); + indexer.pathsChanged({sourceFileIds[0]}); } @@ -458,11 +486,13 @@ TEST_F(SymbolIndexer, IncludeSearchPathsAreDifferent) TEST_F(SymbolIndexer, DontReparseInUpdateProjectPartsIfDefinesAreTheSame) { - ON_CALL(mockStorage, fetchProjectPartArtefact(An())).WillByDefault(Return(artefact)); + InSequence s; - EXPECT_CALL(mockCollector, clear()); - EXPECT_CALL(mockStorage, fetchProjectPartArtefact(TypedEq(projectPart1.projectPartId))); - EXPECT_CALL(mockCollector, addFiles(_, _)).Times(0); + EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); + EXPECT_CALL(mockStorage, fetchProjectPartArtefact(TypedEq(projectPart1.projectPartId))).WillRepeatedly(Return(artefact)); + EXPECT_CALL(mockStorage, insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), Eq(projectPart1.arguments), Eq(projectPart1.compilerMacros), Eq(projectPart1.includeSearchPaths))); + EXPECT_CALL(mockSqliteTransactionBackend, commit()); + EXPECT_CALL(mockCollector, addFile(_, _)).Times(0); EXPECT_CALL(mockCollector, collectSymbols()).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockStorage, addSymbolsAndSourceLocations(_, _)).Times(0); @@ -540,11 +570,12 @@ TEST_F(SymbolIndexer, UpToDateFilesDontPassFilteredUpdatableFilePathIds) TEST_F(SymbolIndexer, OutdatedFilesAreParsedInUpdateProjectParts) { indexer.pathsChanged({main1PathId}); + indexerScheduler.syncTasks(); ON_CALL(mockStorage, fetchProjectPartArtefact(An())).WillByDefault(Return(artefact)); ON_CALL(mockStorage, fetchLowestLastModifiedTime(A())) .WillByDefault(Return(0)); - EXPECT_CALL(mockCollector, addFiles(ElementsAre(main1PathId), _)); + EXPECT_CALL(mockCollector, addFile(Eq(main1PathId), _)); indexer.updateProjectParts({projectPart1}, {}); } @@ -552,11 +583,12 @@ TEST_F(SymbolIndexer, OutdatedFilesAreParsedInUpdateProjectParts) TEST_F(SymbolIndexer, UpToDateFilesAreNotParsedInUpdateProjectParts) { indexer.pathsChanged({main1PathId}); + indexerScheduler.syncTasks(); ON_CALL(mockStorage, fetchProjectPartArtefact(An())).WillByDefault(Return(artefact)); ON_CALL(mockStorage, fetchLowestLastModifiedTime(A())) .WillByDefault(Return(QDateTime::currentSecsSinceEpoch())); - EXPECT_CALL(mockCollector, addFiles(_, _)).Times(0); + EXPECT_CALL(mockCollector, addFile(_, _)).Times(0); indexer.updateProjectParts({projectPart1}, {}); } diff --git a/tests/unit/unittest/symbolindexertaskqueue-test.cpp b/tests/unit/unittest/symbolindexertaskqueue-test.cpp index 17b9f370c4b..5838fed0f92 100644 --- a/tests/unit/unittest/symbolindexertaskqueue-test.cpp +++ b/tests/unit/unittest/symbolindexertaskqueue-test.cpp @@ -25,6 +25,8 @@ #include "googletest.h" +#include "mocksymbolindexertaskscheduler.h" + #include namespace { @@ -48,12 +50,13 @@ MATCHER_P2(IsTask, filePathId, projectPartId, class SymbolIndexerTaskQueue : public testing::Test { protected: - std::size_t projectPartId(const Utils::SmallString &projectPartId) + int projectPartId(const Utils::SmallString &projectPartId) { - return queue.projectPartNumberId(projectPartId); + return int(queue.projectPartNumberId(projectPartId)); } protected: - ClangBackEnd::SymbolIndexerTaskQueue queue; + NiceMock mockSymbolIndexerTaskScheduler; + ClangBackEnd::SymbolIndexerTaskQueue queue{mockSymbolIndexerTaskScheduler}; }; TEST_F(SymbolIndexerTaskQueue, AddTasks) @@ -162,4 +165,52 @@ TEST_F(SymbolIndexerTaskQueue, GetProjectPartIds) ASSERT_THAT(ids , ElementsAre(0, 2, 3)); } + +TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndAddTasksInScheduler) +{ + InSequence s; + queue.addOrUpdateTasks({{{1, 1}, projectPartId("yi"), Callable{}}, + {{1, 3}, projectPartId("yi"), Callable{}}, + {{1, 5}, projectPartId("yi"), Callable{}}}); + + EXPECT_CALL(mockSymbolIndexerTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); + EXPECT_CALL(mockSymbolIndexerTaskScheduler, addTasks(SizeIs(2))); + + queue.processTasks(); +} + +TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndAddTasksWithNoTaskInSchedulerIfTaskAreEmpty) +{ + InSequence s; + + EXPECT_CALL(mockSymbolIndexerTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); + EXPECT_CALL(mockSymbolIndexerTaskScheduler, addTasks(IsEmpty())); + + queue.processTasks(); +} + +TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndMoveAllTasksInSchedulerIfMoreSlotsAreFree) +{ + InSequence s; + queue.addOrUpdateTasks({{{1, 1}, projectPartId("yi"), Callable{}}, + {{1, 3}, projectPartId("yi"), Callable{}}, + {{1, 5}, projectPartId("yi"), Callable{}}}); + + EXPECT_CALL(mockSymbolIndexerTaskScheduler, freeSlots()).WillRepeatedly(Return(4)); + EXPECT_CALL(mockSymbolIndexerTaskScheduler, addTasks(SizeIs(3))); + + queue.processTasks(); +} + +TEST_F(SymbolIndexerTaskQueue, ProcessTasksRemovesProcessedTasks) +{ + queue.addOrUpdateTasks({{{1, 1}, projectPartId("yi"), Callable{}}, + {{1, 3}, projectPartId("yi"), Callable{}}, + {{1, 5}, projectPartId("yi"), Callable{}}}); + ON_CALL(mockSymbolIndexerTaskScheduler, freeSlots()).WillByDefault(Return(2)); + + queue.processTasks(); + + ASSERT_THAT(queue.tasks(), SizeIs(1)); +} } diff --git a/tests/unit/unittest/symbolindexertaskscheduler-test.cpp b/tests/unit/unittest/symbolindexertaskscheduler-test.cpp index d4dff54a388..585102706a6 100644 --- a/tests/unit/unittest/symbolindexertaskscheduler-test.cpp +++ b/tests/unit/unittest/symbolindexertaskscheduler-test.cpp @@ -29,6 +29,7 @@ #include "mocksymbolscollectormanager.h" #include "mocksymbolscollector.h" #include "mocksymbolstorage.h" +#include "mocksqlitetransactionbackend.h" #include @@ -55,18 +56,27 @@ protected: protected: MockFunction mock; ClangBackEnd::SymbolIndexerTaskScheduler::Task call{ - [&] (SymbolsCollectorInterface &symbolsCollector, - SymbolStorageInterface &symbolStorage) { + [&] (SymbolsCollectorInterface &, SymbolStorageInterface &, Sqlite::TransactionInterface &) { mock.Call(); }}; ClangBackEnd::SymbolIndexerTaskScheduler::Task nocall{ - [&] (SymbolsCollectorInterface &symbolsCollector, - SymbolStorageInterface &symbolStorage) {}}; + [&] (SymbolsCollectorInterface &, SymbolStorageInterface &, Sqlite::TransactionInterface &) { + }}; NiceMock mockSymbolsCollectorManager; NiceMock mockSymbolsCollector; MockSymbolStorage mockSymbolStorage; NiceMock mockSymbolIndexerTaskQueue; - ClangBackEnd::SymbolIndexerTaskScheduler scheduler{mockSymbolsCollectorManager, mockSymbolStorage, mockSymbolIndexerTaskQueue, 4}; - ClangBackEnd::SymbolIndexerTaskScheduler deferedScheduler{mockSymbolsCollectorManager, mockSymbolStorage, mockSymbolIndexerTaskQueue, 4, std::launch::deferred}; + MockSqliteTransactionBackend mockSqliteTransactionBackend; + ClangBackEnd::SymbolIndexerTaskScheduler scheduler{mockSymbolsCollectorManager, + mockSymbolStorage, + mockSqliteTransactionBackend, + mockSymbolIndexerTaskQueue, + 4}; + ClangBackEnd::SymbolIndexerTaskScheduler deferedScheduler{mockSymbolsCollectorManager, + mockSymbolStorage, + mockSqliteTransactionBackend, + mockSymbolIndexerTaskQueue, + 4, + std::launch::deferred}; }; TEST_F(SymbolIndexerTaskScheduler, AddTasks) @@ -123,6 +133,7 @@ TEST_F(SymbolIndexerTaskScheduler, NoFuturesAfterFreeSlots) TEST_F(SymbolIndexerTaskScheduler, FreeSlotsCallSymbolsCollectorSetIsUnused) { + InSequence s; scheduler.addTasks({nocall, nocall}); scheduler.syncTasks(); @@ -131,6 +142,17 @@ TEST_F(SymbolIndexerTaskScheduler, FreeSlotsCallSymbolsCollectorSetIsUnused) scheduler.freeSlots(); } +TEST_F(SymbolIndexerTaskScheduler, FreeSlotsCallClearsSymbolsCollector) +{ + InSequence s; + scheduler.addTasks({nocall, nocall}); + scheduler.syncTasks(); + + EXPECT_CALL(mockSymbolsCollector, clear()).Times(2); + + scheduler.freeSlots(); +} + TEST_F(SymbolIndexerTaskScheduler, AddTaskCallSymbolsCollectorManagerUnusedSymbolsCollector) { EXPECT_CALL(mockSymbolsCollectorManager, unusedSymbolsCollector()).Times(2); @@ -140,8 +162,12 @@ TEST_F(SymbolIndexerTaskScheduler, AddTaskCallSymbolsCollectorManagerUnusedSymbo TEST_F(SymbolIndexerTaskScheduler, CallProcessTasksInQueueAfterFinishedTasks) { - EXPECT_CALL(mockSymbolIndexerTaskQueue, processTasks()).Times(2); + InSequence s; - scheduler.addTasks({nocall, nocall}); + EXPECT_CALL(mock, Call()); + EXPECT_CALL(mockSymbolIndexerTaskQueue, processTasks()); + + scheduler.addTasks({call}); + scheduler.syncTasks(); } } diff --git a/tests/unit/unittest/symbolindexing-test.cpp b/tests/unit/unittest/symbolindexing-test.cpp index 1971379fd6f..916867e4b3b 100644 --- a/tests/unit/unittest/symbolindexing-test.cpp +++ b/tests/unit/unittest/symbolindexing-test.cpp @@ -96,6 +96,7 @@ protected: TEST_F(SymbolIndexing, Locations) { indexing.indexer().updateProjectParts({projectPart1}, {}); + indexing.syncTasks(); auto locations = query.locationsAt(filePathId(TESTDATA_DIR "/symbolindexing_main1.cpp"), 1, 6); ASSERT_THAT(locations, @@ -108,6 +109,7 @@ TEST_F(SymbolIndexing, Locations) TEST_F(SymbolIndexing, DISABLED_TemplateFunction) { indexing.indexer().updateProjectParts({projectPart1}, {}); + indexing.syncTasks(); auto locations = query.locationsAt(filePathId(TESTDATA_DIR "/symbolindexing_main1.cpp"), 21, 24); ASSERT_THAT(locations, @@ -122,6 +124,8 @@ TEST_F(SymbolIndexing, PathsAreUpdated) indexing.indexer().pathsChanged({filePathId(main1Path)}); indexing.indexer().pathsChanged({filePathId(main1Path)}); + indexing.syncTasks(); + auto locations = query.locationsAt(filePathId(TESTDATA_DIR "/symbolindexing_main1.cpp"), 1, 6); ASSERT_THAT(locations, ElementsAre( diff --git a/tests/unit/unittest/symbolscollector-test.cpp b/tests/unit/unittest/symbolscollector-test.cpp index 7b8bafe8f08..f20e26b7f51 100644 --- a/tests/unit/unittest/symbolscollector-test.cpp +++ b/tests/unit/unittest/symbolscollector-test.cpp @@ -173,7 +173,7 @@ protected: Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; FilePathCaching filePathCache{database}; - ClangBackEnd::SymbolsCollector collector{filePathCache}; + ClangBackEnd::SymbolsCollector collector{database}; }; TEST_F(SymbolsCollector, CollectSymbolName) diff --git a/tests/unit/unittest/symbolscollectormanager-test.cpp b/tests/unit/unittest/symbolscollectormanager-test.cpp new file mode 100644 index 00000000000..18b210b80a2 --- /dev/null +++ b/tests/unit/unittest/symbolscollectormanager-test.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** 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 "googletest.h" + +#include "mocksymbolscollector.h" + +#include +#include +#include + +namespace { + +class SymbolsCollectorManager : public testing::Test +{ +protected: + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; + ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; + ClangBackEnd::SymbolsCollectorManager> manager{database}; +}; + +TEST_F(SymbolsCollectorManager, CreateUnsedSystemCollector) +{ + manager.unusedSymbolsCollector(); + + manager.unusedSymbolsCollector(); + + ASSERT_THAT(manager.collectors(), SizeIs(2)); +} + +TEST_F(SymbolsCollectorManager, ReuseUnsedSystemCollector) +{ + auto &collector = manager.unusedSymbolsCollector(); + collector.setIsUsed(false); + + manager.unusedSymbolsCollector(); + + ASSERT_THAT(manager.collectors(), SizeIs(1)); +} + +TEST_F(SymbolsCollectorManager, AsGetNewUnusedSymbolsCollectorItIsSetUsed) +{ + auto &collector = manager.unusedSymbolsCollector(); + + ASSERT_TRUE(collector.isUsed()); +} + +TEST_F(SymbolsCollectorManager, AsGetReusedUnusedSymbolsCollectorItIsSetUsed) +{ + auto &collector = manager.unusedSymbolsCollector(); + collector.setIsUsed(false); + + auto &collector2 = manager.unusedSymbolsCollector(); + + ASSERT_TRUE(collector2.isUsed()); +} + +} diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index a0faff8dddb..c35d8c7144a 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -194,7 +194,7 @@ TEST_F(SymbolStorage, InsertProjectPart) TypedEq("[\"foo\"]"), TypedEq("{\"FOO\":\"1\"}"), TypedEq("[\"/includes\"]"))); - EXPECT_CALL(mockDatabase, lastInsertedRowId()); + EXPECT_CALL(mockDatabase, lastInsertedRowId()).Times(2); storage.insertOrUpdateProjectPart("project", {"foo"}, {{"FOO", "1"}}, {"/includes"}); } @@ -216,6 +216,7 @@ TEST_F(SymbolStorage, UpdateProjectPart) TypedEq("{\"FOO\":\"1\"}"), TypedEq("[\"/includes\"]"), TypedEq("project"))); + EXPECT_CALL(mockDatabase, lastInsertedRowId()); storage.insertOrUpdateProjectPart("project", {"foo"}, {{"FOO", "1"}}, {"/includes"}); } diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 126113d9a45..d329900d1ea 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -97,7 +97,8 @@ SOURCES += \ generatedfiles-test.cpp \ sourcesmanager-test.cpp \ symbolindexertaskqueue-test.cpp \ - symbolindexertaskscheduler-test.cpp + symbolindexertaskscheduler-test.cpp \ + symbolscollectormanager-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ @@ -174,7 +175,7 @@ SOURCES += \ symbolindexing-test.cpp \ symbolscollector-test.cpp \ symbolfinder-test.cpp \ - testclangtool.cpp \ + testclangtool.cpp } exists($$GOOGLEBENCHMARK_DIR) { @@ -235,7 +236,9 @@ HEADERS += \ mockprecompiledheaderstorage.h \ mockeditormanager.h \ mocksymbolscollectormanager.h \ - mocksymbolindexertaskqueue.h + mocksymbolindexertaskqueue.h \ + mocksymbolindexertaskscheduler.h + !isEmpty(LIBCLANG_LIBS) { HEADERS += \ chunksreportedmonitor.h \