diff --git a/src/plugins/clangpchmanager/clangpchmanager-source.pri b/src/plugins/clangpchmanager/clangpchmanager-source.pri index 98010437c09..27e35dc7409 100644 --- a/src/plugins/clangpchmanager/clangpchmanager-source.pri +++ b/src/plugins/clangpchmanager/clangpchmanager-source.pri @@ -12,10 +12,7 @@ HEADERS += \ $$PWD/pchmanagerconnectionclient.h \ $$PWD/clangpchmanager_global.h \ $$PWD/projectupdater.h \ - $$PWD/pchmanagerprojectupdater.h \ - $$PWD/precompiledheaderstorage.h \ - $$PWD/precompiledheaderstorageinterface.h - + $$PWD/pchmanagerprojectupdater.h SOURCES += \ $$PWD/pchmanagerclient.cpp \ @@ -23,4 +20,3 @@ SOURCES += \ $$PWD/pchmanagerconnectionclient.cpp \ $$PWD/projectupdater.cpp \ $$PWD/pchmanagerprojectupdater.cpp - diff --git a/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp b/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp index 5817db90344..098faf50b31 100644 --- a/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp +++ b/src/plugins/clangpchmanager/clangpchmanagerplugin.cpp @@ -27,7 +27,6 @@ #include "pchmanagerconnectionclient.h" #include "pchmanagerclient.h" -#include "precompiledheaderstorage.h" #include "qtcreatorprojectupdater.h" #include @@ -62,8 +61,7 @@ public: Sqlite::Database database{Utils::PathString{Core::ICore::userResourcePath() + "/symbol-experimental-v1.db"}, 1000ms}; ClangBackEnd::RefactoringDatabaseInitializer databaseInitializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; - PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; - PchManagerClient pchManagerClient{preCompiledHeaderStorage}; + PchManagerClient pchManagerClient; PchManagerConnectionClient connectionClient{&pchManagerClient}; QtCreatorProjectUpdater projectUpdate{connectionClient.serverProxy(), pchManagerClient, diff --git a/src/plugins/clangpchmanager/pchmanagerclient.cpp b/src/plugins/clangpchmanager/pchmanagerclient.cpp index e5321865cee..81af53308e5 100644 --- a/src/plugins/clangpchmanager/pchmanagerclient.cpp +++ b/src/plugins/clangpchmanager/pchmanagerclient.cpp @@ -34,11 +34,6 @@ namespace ClangPchManager { -PchManagerClient::PchManagerClient(PrecompiledHeaderStorageInterface &precompiledHeaderStorage) - : m_precompiledHeaderStorage(precompiledHeaderStorage) -{ -} - void PchManagerClient::alive() { if (m_connectionClient) @@ -50,7 +45,6 @@ void PchManagerClient::precompiledHeadersUpdated(ClangBackEnd::PrecompiledHeader for (ClangBackEnd::ProjectPartPch &projectPartPch : message.takeProjectPartPchs()) { const QString projectPartId{projectPartPch.projectPartId}; const QString pchPath{projectPartPch.pchPath}; - addPchToDatabase(projectPartPch); addProjectPartPch(std::move(projectPartPch)); precompiledHeaderUpdated(projectPartId, pchPath, projectPartPch.lastModified); } @@ -60,7 +54,6 @@ void PchManagerClient::precompiledHeaderRemoved(const QString &projectPartId) { for (auto notifier : m_notifiers) { Utils::SmallString id(projectPartId); - removePchFromDatabase(id); removeProjectPartPch(id); notifier->precompiledHeaderRemoved(projectPartId); } @@ -117,18 +110,6 @@ void PchManagerClient::removeProjectPartPch(Utils::SmallStringView projectPartId } } -void PchManagerClient::addPchToDatabase(const ClangBackEnd::ProjectPartPch &projectPartPch) -{ - m_precompiledHeaderStorage.insertPrecompiledHeader(projectPartPch.projectPartId, - projectPartPch.pchPath, - projectPartPch.lastModified); -} - -void PchManagerClient::removePchFromDatabase(const Utils::SmallStringView &projectPartId) -{ - m_precompiledHeaderStorage.deletePrecompiledHeader(projectPartId); -} - void PchManagerClient::addProjectPartPch(ClangBackEnd::ProjectPartPch &&projectPartPch) { auto found = std::lower_bound(m_projectPartPchs.begin(), diff --git a/src/plugins/clangpchmanager/pchmanagerclient.h b/src/plugins/clangpchmanager/pchmanagerclient.h index e9b80ebe513..92c44465f23 100644 --- a/src/plugins/clangpchmanager/pchmanagerclient.h +++ b/src/plugins/clangpchmanager/pchmanagerclient.h @@ -26,7 +26,6 @@ #pragma once #include "clangpchmanager_global.h" -#include "precompiledheaderstorageinterface.h" #include #include @@ -43,7 +42,7 @@ class CLANGPCHMANAGER_EXPORT PchManagerClient final : public ClangBackEnd::PchMa { friend class PchManagerNotifierInterface; public: - PchManagerClient(PrecompiledHeaderStorageInterface &precompiledHeaderStorage); + PchManagerClient() = default; void alive() override; void precompiledHeadersUpdated(ClangBackEnd::PrecompiledHeadersUpdatedMessage &&message) override; @@ -71,14 +70,10 @@ unittest_public: void addProjectPartPch(ClangBackEnd::ProjectPartPch &&projectPartPch); void removeProjectPartPch(Utils::SmallStringView projectPartId); - void addPchToDatabase(const ClangBackEnd::ProjectPartPch &projectPartPch); - void removePchFromDatabase(const Utils::SmallStringView &projectPartId); - private: ClangBackEnd::ProjectPartPchs m_projectPartPchs; std::vector m_notifiers; PchManagerConnectionClient *m_connectionClient=nullptr; - PrecompiledHeaderStorageInterface &m_precompiledHeaderStorage; }; } // namespace ClangPchManager diff --git a/src/plugins/clangpchmanager/projectupdater.cpp b/src/plugins/clangpchmanager/projectupdater.cpp index 81d140d3f75..a3fbb6cb621 100644 --- a/src/plugins/clangpchmanager/projectupdater.cpp +++ b/src/plugins/clangpchmanager/projectupdater.cpp @@ -72,9 +72,10 @@ void ProjectUpdater::updateProjectParts(const std::vector #include #include -#include #include #include +#include +#include #include +#include #include #include #include +#include #include #include @@ -53,9 +56,9 @@ using ClangBackEnd::ClangPathWatcher; using ClangBackEnd::ConnectionServer; using ClangBackEnd::GeneratedFiles; using ClangBackEnd::PchCreator; -using ClangBackEnd::PchGenerator; using ClangBackEnd::PchManagerClientProxy; using ClangBackEnd::PchManagerServer; +using ClangBackEnd::PrecompiledHeaderStorage; using ClangBackEnd::ProjectParts; using ClangBackEnd::FilePathCache; @@ -121,6 +124,61 @@ QStringList processArguments(QCoreApplication &application) return parser.positionalArguments(); } +class PchCreatorManager final : public ClangBackEnd::ProcessorManager +{ +public: + using Processor = ClangBackEnd::PchCreator; + PchCreatorManager(const ClangBackEnd::GeneratedFiles &generatedFiles, + ClangBackEnd::Environment &environment, + Sqlite::Database &database, + PchManagerServer &pchManagerServer, + ClangBackEnd::ClangPathWatcherInterface &fileSystemWatcher) + : ProcessorManager(generatedFiles), + m_environment(environment), + m_database(database), + m_pchManagerServer(pchManagerServer), + m_fileSystemWatcher(fileSystemWatcher) + {} + +protected: + std::unique_ptr createProcessor() const override + { + return std::make_unique(m_environment, + m_database, + *m_pchManagerServer.client(), + m_fileSystemWatcher); + } + +private: + ClangBackEnd::Environment &m_environment; + Sqlite::Database &m_database; + ClangBackEnd::PchManagerServer &m_pchManagerServer; + ClangBackEnd::ClangPathWatcherInterface &m_fileSystemWatcher; +}; + +struct Data // because we have a cycle dependency +{ + using TaskScheduler = ClangBackEnd::TaskScheduler; + + Data(const QString &databasePath, + const QString &pchsPath) + : database{Utils::PathString{databasePath}, 100000ms}, + environment{pchsPath} + {} + Sqlite::Database database; + ClangBackEnd::RefactoringDatabaseInitializer databaseInitializer{database}; + ClangBackEnd::FilePathCaching filePathCache{database}; + ClangPathWatcher includeWatcher{filePathCache}; + ApplicationEnvironment environment; + ProjectParts projectParts; + GeneratedFiles generatedFiles; + PchCreatorManager pchCreatorManager{generatedFiles, environment, database, clangPchManagerServer, includeWatcher}; + PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; + TaskScheduler taskScheduler{pchCreatorManager, projectPartQueue, std::thread::hardware_concurrency()}; + ClangBackEnd::ProjectPartQueue projectPartQueue{taskScheduler, preCompiledHeaderStorage, database}; + PchManagerServer clangPchManagerServer{includeWatcher, projectPartQueue, projectParts, generatedFiles}; +}; + int main(int argc, char *argv[]) { try { @@ -138,25 +196,12 @@ int main(int argc, char *argv[]) const QString databasePath = arguments[1]; const QString pchsPath = arguments[2]; - Sqlite::Database database{Utils::PathString{databasePath}, 100000ms}; - ClangBackEnd::RefactoringDatabaseInitializer databaseInitializer{database}; - ClangBackEnd::FilePathCaching filePathCache{database}; - ClangPathWatcher includeWatcher(filePathCache); - ApplicationEnvironment environment{pchsPath}; - PchGenerator pchGenerator(environment); - GeneratedFiles generatedFiles; - PchCreator pchCreator(environment, filePathCache, generatedFiles); - pchCreator.setGenerator(&pchGenerator); - ProjectParts projectParts; - PchManagerServer clangPchManagerServer(includeWatcher, - pchCreator, - projectParts, - generatedFiles); - includeWatcher.setNotifier(&clangPchManagerServer); - pchGenerator.setNotifier(&clangPchManagerServer); + Data data{databasePath, pchsPath}; + + data.includeWatcher.setNotifier(&data.clangPchManagerServer); ConnectionServer connectionServer; - connectionServer.setServer(&clangPchManagerServer); + connectionServer.setServer(&data.clangPchManagerServer); connectionServer.start(connectionName); return application.exec(); diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri index 9556f50cd13..c6cf9659920 100644 --- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri +++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri @@ -2,7 +2,8 @@ INCLUDEPATH += $$PWD SOURCES += \ $$PWD/pchmanagerserver.cpp \ - $$PWD/projectparts.cpp + $$PWD/projectparts.cpp \ + $$PWD/projectpartqueue.cpp HEADERS += \ $$PWD/pchmanagerserver.h \ @@ -12,9 +13,15 @@ HEADERS += \ $$PWD/projectparts.h \ $$PWD/pchcreatorinterface.h \ $$PWD/projectpartsinterface.h \ - $$PWD/pchgenerator.h \ - $$PWD/pchgeneratornotifierinterface.h \ - $$PWD/pchgeneratorinterface.h + $$PWD/projectpartqueue.h \ + $$PWD/queueinterface.h \ + $$PWD/projectpartqueueinterface.h \ + $$PWD/processormanagerinterface.h \ + $$PWD/processorinterface.h \ + $$PWD/taskscheduler.h \ + $$PWD/taskschedulerinterface.h \ + $$PWD/precompiledheaderstorage.h \ + $$PWD/precompiledheaderstorageinterface.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ @@ -26,5 +33,6 @@ HEADERS += \ $$PWD/collectincludestoolaction.h \ $$PWD/collectincludesaction.h \ $$PWD/collectincludespreprocessorcallbacks.h \ - $$PWD/pchcreator.h + $$PWD/pchcreator.h \ + $$PWD/processormanager.h } diff --git a/src/tools/clangpchmanagerbackend/source/collectincludesaction.h b/src/tools/clangpchmanagerbackend/source/collectincludesaction.h index 923cf5bfc0c..d55559b41e0 100644 --- a/src/tools/clangpchmanagerbackend/source/collectincludesaction.h +++ b/src/tools/clangpchmanagerbackend/source/collectincludesaction.h @@ -41,7 +41,7 @@ class CollectIncludesAction final : public clang::PreprocessOnlyAction public: CollectIncludesAction(FilePathIds &includeIds, FilePathIds &topIncludeIds, - FilePathCachingInterface &filePathCache, + const FilePathCachingInterface &filePathCache, std::vector &excludedIncludeUID, std::vector &alreadyIncludedFileUIDs) : m_includeIds(includeIds), @@ -56,12 +56,10 @@ public: { if (clang::PreprocessOnlyAction::BeginSourceFileAction(compilerInstance)) { auto &preprocessor = compilerInstance.getPreprocessor(); - auto &headerSearch = preprocessor.getHeaderSearchInfo(); preprocessor.SetSuppressIncludeNotFoundError(true); auto macroPreprocessorCallbacks = new CollectIncludesPreprocessorCallbacks( - headerSearch, m_includeIds, m_topIncludeIds, m_filePathCache, @@ -85,7 +83,7 @@ public: private: FilePathIds &m_includeIds; FilePathIds &m_topIncludeIds; - FilePathCachingInterface &m_filePathCache; + const FilePathCachingInterface &m_filePathCache; std::vector &m_excludedIncludeUID; std::vector &m_alreadyIncludedFileUIDs; }; diff --git a/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h index 645d87e91d5..2a6d0a54d8c 100644 --- a/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h @@ -48,15 +48,13 @@ namespace ClangBackEnd { class CollectIncludesPreprocessorCallbacks final : public clang::PPCallbacks { public: - CollectIncludesPreprocessorCallbacks(clang::HeaderSearch &headerSearch, - FilePathIds &includeIds, + CollectIncludesPreprocessorCallbacks(FilePathIds &includeIds, FilePathIds &topIncludeIds, - FilePathCachingInterface &filePathCache, + const FilePathCachingInterface &filePathCache, const std::vector &excludedIncludeUID, std::vector &alreadyIncludedFileUIDs, clang::SourceManager &sourceManager) - : m_headerSearch(headerSearch), - m_includeIds(includeIds), + : m_includeIds(includeIds), m_topIncludeIds(topIncludeIds), m_filePathCache(filePathCache), m_excludedIncludeUID(excludedIncludeUID), @@ -159,10 +157,9 @@ public: } private: - clang::HeaderSearch &m_headerSearch; FilePathIds &m_includeIds; FilePathIds &m_topIncludeIds; - FilePathCachingInterface &m_filePathCache; + const FilePathCachingInterface &m_filePathCache; const std::vector &m_excludedIncludeUID; std::vector &m_alreadyIncludedFileUIDs; clang::SourceManager &m_sourceManager; diff --git a/src/tools/clangpchmanagerbackend/source/collectincludestoolaction.h b/src/tools/clangpchmanagerbackend/source/collectincludestoolaction.h index e5c30829fa5..a9c6e9717e2 100644 --- a/src/tools/clangpchmanagerbackend/source/collectincludestoolaction.h +++ b/src/tools/clangpchmanagerbackend/source/collectincludestoolaction.h @@ -39,7 +39,7 @@ class CollectIncludesToolAction final : public clang::tooling::FrontendActionFac public: CollectIncludesToolAction(FilePathIds &includeIds, FilePathIds &topIncludeIds, - FilePathCachingInterface &filePathCache, + const FilePathCachingInterface &filePathCache, const Utils::PathStringVector &excludedIncludes) : m_includeIds(includeIds), m_topIncludeIds(topIncludeIds), @@ -93,7 +93,7 @@ private: std::vector m_excludedIncludeUIDs; FilePathIds &m_includeIds; FilePathIds &m_topIncludeIds; - FilePathCachingInterface &m_filePathCache; + const FilePathCachingInterface &m_filePathCache; const Utils::PathStringVector &m_excludedIncludes; }; diff --git a/src/tools/clangpchmanagerbackend/source/includecollector.cpp b/src/tools/clangpchmanagerbackend/source/includecollector.cpp index 3c93de82b28..6be1533353d 100644 --- a/src/tools/clangpchmanagerbackend/source/includecollector.cpp +++ b/src/tools/clangpchmanagerbackend/source/includecollector.cpp @@ -33,7 +33,7 @@ namespace ClangBackEnd { -IncludeCollector::IncludeCollector(FilePathCachingInterface &filePathCache) +IncludeCollector::IncludeCollector(const FilePathCachingInterface &filePathCache) : m_filePathCache(filePathCache) { } diff --git a/src/tools/clangpchmanagerbackend/source/includecollector.h b/src/tools/clangpchmanagerbackend/source/includecollector.h index fc3c1a59910..30dd89d4704 100644 --- a/src/tools/clangpchmanagerbackend/source/includecollector.h +++ b/src/tools/clangpchmanagerbackend/source/includecollector.h @@ -34,7 +34,7 @@ namespace ClangBackEnd { class IncludeCollector : public ClangTool { public: - IncludeCollector(FilePathCachingInterface &filePathCache); + IncludeCollector(const FilePathCachingInterface &filePathCache); void collectIncludes(); @@ -48,7 +48,7 @@ private: FilePathIds m_includeIds; FilePathIds m_topIncludeIds; Utils::SmallStringVector m_directories; - FilePathCachingInterface &m_filePathCache; + const FilePathCachingInterface &m_filePathCache; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index fb7ccaae53a..e02f563efee 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -29,39 +29,21 @@ #include "includecollector.h" #include "pchnotcreatederror.h" +#include #include #include +#include +#include #include #include #include #include +#include #include namespace ClangBackEnd { -PchCreator::PchCreator(Environment &environment, - FilePathCachingInterface &filePathCache, - const GeneratedFiles &generatedFiles) - : m_generatedFiles(generatedFiles), - m_environment(environment), - m_filePathCache(filePathCache) -{ -} - -PchCreator::PchCreator(V2::ProjectPartContainers &&projectsParts, - Environment &environment, - FilePathCachingInterface &filePathCache, - PchGeneratorInterface *pchGenerator, - const GeneratedFiles &generatedFiles) - : m_projectParts(std::move(projectsParts)), - m_generatedFiles(generatedFiles), - m_environment(environment), - m_filePathCache(filePathCache), - m_pchGenerator(pchGenerator) -{ -} - namespace { template @@ -76,16 +58,6 @@ void append(Target &target, const Source &source) target.push_back(ValueType(std::move(entry))); } -template -void append(Target &target, Source &source) -{ - target.reserve(target.size() + source.size()); - - for (auto &&entry : source) - target.emplace_back(entry); -} - void appendFilePathId(Utils::PathStringVector &target, const ClangBackEnd::FilePathIds &source, const ClangBackEnd::FilePathCachingInterface &filePathCache) @@ -94,51 +66,6 @@ void appendFilePathId(Utils::PathStringVector &target, target.emplace_back(filePathCache.filePath(id).path()); } -template -std::size_t globalCount(const V2::ProjectPartContainers &projectsParts, - GetterFunction getterFunction) -{ - auto sizeFunction = [&] (std::size_t size, const V2::ProjectPartContainer &projectContainer) { - return size + getterFunction(projectContainer).size(); - }; - - return std::accumulate(projectsParts.begin(), - projectsParts.end(), - std::size_t(0), - sizeFunction); -} - -template -void generateGlobal(Container &entries, - const V2::ProjectPartContainers &projectsParts, - GetterFunction getterFunction) -{ - entries.reserve(entries.capacity() + globalCount(projectsParts, getterFunction)); - - for (const V2::ProjectPartContainer &projectPart : projectsParts) { - auto &&projectPartPaths = getterFunction(projectPart); - - append(entries, projectPartPaths); - }; -} - -template -Utils::PathStringVector generateGlobal( - const V2::ProjectPartContainers &projectsParts, - GetterFunction getterFunction, - std::size_t prereserve = 0) -{ - Container entries; - entries.reserve(prereserve); - - generateGlobal(entries, projectsParts, getterFunction); - - return entries; -} - - Utils::PathStringVector generatedFilePaths(const V2::FileContainers &generaredFiles) { Utils::PathStringVector generaredFilePaths; @@ -152,114 +79,6 @@ Utils::PathStringVector generatedFilePaths(const V2::FileContainers &generaredFi } -Utils::PathStringVector PchCreator::generateGlobalHeaderPaths() const -{ - auto includeFunction = [&] (const V2::ProjectPartContainer &projectPart) { - return m_filePathCache.filePaths(projectPart.headerPathIds); - }; - - Utils::PathStringVector headerPaths = generateGlobal(m_projectParts, - includeFunction, - m_generatedFiles.fileContainers().size()); - - Utils::PathStringVector generatedPath = generatedFilePaths(m_generatedFiles.fileContainers()); - - headerPaths.insert(headerPaths.end(), - std::make_move_iterator(generatedPath.begin()), - std::make_move_iterator(generatedPath.end())); - - return headerPaths; -} - -Utils::PathStringVector PchCreator::generateGlobalSourcePaths() const -{ - auto sourceFunction = [&] (const V2::ProjectPartContainer &projectPart) { - return m_filePathCache.filePaths(projectPart.sourcePathIds); - }; - - return generateGlobal(m_projectParts, sourceFunction); -} - -Utils::PathStringVector PchCreator::generateGlobalHeaderAndSourcePaths() const -{ - const auto &sourcePaths = generateGlobalSourcePaths(); - auto includePaths = generateGlobalHeaderPaths(); - - append(includePaths, sourcePaths); - - return includePaths; -} - -Utils::SmallStringVector PchCreator::generateGlobalArguments() const -{ - Utils::SmallStringVector arguments; - - auto argumentFunction = [] (const V2::ProjectPartContainer &projectPart) - -> const Utils::SmallStringVector & { - return projectPart.arguments; - }; - - generateGlobal(arguments, m_projectParts, argumentFunction); - - return arguments; -} - -Utils::SmallStringVector PchCreator::generateGlobalCommandLine() const -{ - Utils::SmallStringVector commandLine; - commandLine.emplace_back(m_environment.clangCompilerPath()); - - auto argumentFunction = [] (const V2::ProjectPartContainer &projectPart) - -> const Utils::SmallStringVector & { - return projectPart.arguments; - }; - - generateGlobal(commandLine, m_projectParts, argumentFunction); - - return commandLine; -} - -Utils::SmallStringVector PchCreator::generateGlobalPchCompilerArguments() const -{ - Utils::SmallStringVector arguments; - arguments.reserve(5); - - arguments.emplace_back("-x"); - arguments.emplace_back("c++-header"); - arguments.emplace_back("-Xclang"); - arguments.emplace_back("-emit-pch"); - arguments.emplace_back("-o"); - arguments.emplace_back(generateGlobalPchFilePath()); - arguments.emplace_back(generateGlobalPchHeaderFilePath()); - - return arguments; -} - -Utils::SmallStringVector PchCreator::generateGlobalClangCompilerArguments() const -{ - auto compilerArguments = generateGlobalArguments(); - const auto pchArguments = generateGlobalPchCompilerArguments(); - - append(compilerArguments, pchArguments); - - return compilerArguments; -} - -FilePathIds PchCreator::generateGlobalPchIncludeIds() const -{ - IncludeCollector collector(m_filePathCache); - - collector.setExcludedIncludes(generateGlobalSourcePaths()); - - collector.addFiles(generateGlobalHeaderAndSourcePaths(), generateGlobalCommandLine()); - - collector.addUnsavedFiles(m_generatedFiles.fileContainers()); - - collector.collectIncludes(); - - return collector.takeIncludeIds(); -} - namespace { std::size_t contentSize(const FilePaths &includes) @@ -286,28 +105,19 @@ Utils::SmallString PchCreator::generatePchIncludeFileContent(const FilePathIds & return fileContent; } -Utils::SmallString PchCreator::generateGlobalPchHeaderFileContent() const -{ - return generatePchIncludeFileContent(generateGlobalPchIncludeIds()); -} -std::unique_ptr PchCreator::generateGlobalPchHeaderFile() +bool PchCreator::generatePch(Utils::SmallStringVector &&compilerArguments) { - return generateFileWithContent(generateGlobalPchHeaderFilePath(), - generateGlobalPchHeaderFileContent()); -} + QProcess process; -void PchCreator::generatePch(Utils::SmallStringVector &&compilerArguments, - ProjectPartPch &&projectPartPch) -{ - m_pchGenerator->startTask(std::move(compilerArguments), std::move(projectPartPch)); -} + process.setProcessChannelMode(QProcess::ForwardedChannels); + process.setArguments(QStringList(compilerArguments)); + process.setProgram(QString(m_environment.clangCompilerPath())); -void PchCreator::generateGlobalPch() -{ - generateGlobalPchHeaderFile(); + process.start(); + process.waitForFinished(300000); - generatePch(generateGlobalClangCompilerArguments(), ProjectPartPch()); + return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; } QStringList PchCreator::convertToQStringList(const Utils::SmallStringVector &compilerArguments) @@ -324,52 +134,13 @@ namespace { void hashProjectPart(QCryptographicHash &hash, const V2::ProjectPartContainer &projectPart) { const auto &projectPartId = projectPart.projectPartId; - hash.addData(projectPartId.data(), projectPartId.size()); + hash.addData(projectPartId.data(), int(projectPartId.size())); for (const auto &argument : projectPart.arguments) - hash.addData(argument.data(), argument.size()); + hash.addData(argument.data(), int(argument.size())); } } -QByteArray PchCreator::globalProjectHash() const -{ - QCryptographicHash hash(QCryptographicHash::Sha1); - - for (const auto &projectPart : m_projectParts) - hashProjectPart(hash, projectPart); - - auto result = hash.result(); - - return result.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); -} - -Utils::SmallString PchCreator::generateGlobalPchFilePathWithoutExtension() const -{ - QByteArray fileName = m_environment.pchBuildDirectory().toUtf8(); - fileName += '/'; - fileName += globalProjectHash(); - - return Utils::SmallString::fromQByteArray(fileName); -} - -Utils::SmallString PchCreator::generateGlobalPchHeaderFilePath() const -{ - Utils::SmallString filePath = generateGlobalPchFilePathWithoutExtension(); - - filePath += ".h"; - - return filePath; -} - -Utils::SmallString PchCreator::generateGlobalPchFilePath() const -{ - Utils::SmallString filePath = generateGlobalPchFilePathWithoutExtension(); - - filePath += ".pch"; - - return filePath; -} - Utils::SmallStringVector PchCreator::generateProjectPartCommandLine( const V2::ProjectPartContainer &projectPart) const { @@ -399,7 +170,7 @@ Utils::PathStringVector PchCreator::generateProjectPartHeaders( const V2::ProjectPartContainer &projectPart) const { Utils::PathStringVector headerPaths; - headerPaths.reserve(projectPart.headerPathIds.size() + m_generatedFiles.fileContainers().size()); + headerPaths.reserve(projectPart.headerPathIds.size() + m_unsavedFiles.size()); std::transform(projectPart.headerPathIds.begin(), projectPart.headerPathIds.end(), @@ -408,7 +179,7 @@ Utils::PathStringVector PchCreator::generateProjectPartHeaders( return m_filePathCache.filePath(filePathId); }); - Utils::PathStringVector generatedPath = generatedFilePaths(m_generatedFiles.fileContainers()); + Utils::PathStringVector generatedPath = generatedFilePaths(m_unsavedFiles); std::copy(std::make_move_iterator(generatedPath.begin()), std::make_move_iterator(generatedPath.end()), @@ -484,7 +255,7 @@ std::pair PchCreator::generateProjectPartPchIncludes( {}, arguments); - collector.addUnsavedFiles(m_generatedFiles.fileContainers()); + collector.addUnsavedFiles(m_unsavedFiles); collector.collectIncludes(); @@ -549,35 +320,68 @@ IdPaths PchCreator::generateProjectPartPch(const V2::ProjectPartContainer &proje auto pchFilePath = generateProjectPartPchFilePath(projectPart); generateFileWithContent(pchIncludeFilePath, content); - generatePch(generateProjectPartClangCompilerArguments(projectPart), - {projectPart.projectPartId.clone(), std::move(pchFilePath), lastModified}); + bool success = generatePch(generateProjectPartClangCompilerArguments(projectPart)); + + m_projectPartPch.projectPartId = projectPart.projectPartId; + + if (success) { + m_projectPartPch.pchPath = std::move(pchFilePath); + m_projectPartPch.lastModified = lastModified; + } return {projectPart.projectPartId.clone(), std::move(allExternalIncludes)}; } -void PchCreator::generatePchs() +void PchCreator::generatePch(const V2::ProjectPartContainer &projectPart) { - for (const V2::ProjectPartContainer &projectPart : m_projectParts) { - auto includePaths = generateProjectPartPch(projectPart); - m_projectsIncludeIds.push_back(std::move(includePaths)); - } + m_projectIncludeIds = generateProjectPartPch(projectPart); } -void PchCreator::generatePchs(V2::ProjectPartContainers &&projectsParts) +IdPaths PchCreator::takeProjectIncludes() { - m_projectParts = std::move(projectsParts); - - generatePchs(); + return std::move(m_projectIncludeIds); } -std::vector PchCreator::takeProjectsIncludes() +const ProjectPartPch &PchCreator::projectPartPch() { - return std::move(m_projectsIncludeIds); + return m_projectPartPch; } -void PchCreator::setGenerator(PchGeneratorInterface *pchGenerator) +void PchCreator::setUnsavedFiles(const V2::FileContainers &fileContainers) { - m_pchGenerator = pchGenerator; + m_unsavedFiles = fileContainers; +} + +void PchCreator::setIsUsed(bool isUsed) +{ + m_isUsed = isUsed; +} + +bool PchCreator::isUsed() const +{ + return m_isUsed; +} + +void PchCreator::clear() +{ + m_projectPartPch = ProjectPartPch{}; + m_projectIncludeIds = IdPaths{}; +} + +void PchCreator::doInMainThreadAfterFinished() +{ + m_pchManagerClient.precompiledHeadersUpdated(ProjectPartPchs{m_projectPartPch}); + m_fileSystemWatcher.updateIdPaths({takeProjectIncludes()}); +} + +const IdPaths &PchCreator::projectIncludes() const +{ + return m_projectIncludeIds; +} + +const FilePathCaching &PchCreator::filePathCache() +{ + return m_filePathCache; } std::unique_ptr PchCreator::generateFileWithContent( diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.h b/src/tools/clangpchmanagerbackend/source/pchcreator.h index 65425296b62..b3e0dcde565 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.h @@ -27,10 +27,9 @@ #include "pchcreatorinterface.h" -#include "pchgeneratorinterface.h" #include "idpaths.h" -#include +#include #include #include @@ -44,50 +43,40 @@ namespace ClangBackEnd { class Environment; class GeneratedFiles; +class PchManagerClientInterface; +class ClangPathWatcherInterface; class PchCreator final : public PchCreatorInterface { public: PchCreator(Environment &environment, - FilePathCachingInterface &filePathCache, - const GeneratedFiles &generatedFiles); - PchCreator(V2::ProjectPartContainers &&projectsParts, - Environment &environment, - FilePathCachingInterface &filePathCache, - PchGeneratorInterface *pchGenerator, - const GeneratedFiles &generatedFiles); + Sqlite::Database &database, + PchManagerClientInterface &pchManagerClient, + ClangPathWatcherInterface &fileSystemWatcher) + : m_filePathCache(database), + m_environment(environment), + m_pchManagerClient(pchManagerClient), + m_fileSystemWatcher(fileSystemWatcher) + { + } - void generatePchs(V2::ProjectPartContainers &&projectsParts) override; - std::vector takeProjectsIncludes() override; + void generatePch(const V2::ProjectPartContainer &projectsPart) override; + IdPaths takeProjectIncludes() override; + const ProjectPartPch &projectPartPch() override; + void setUnsavedFiles(const V2::FileContainers &fileContainers) override; + void setIsUsed(bool isUsed) override; + bool isUsed() const override; + void clear() override; + void doInMainThreadAfterFinished() override; - void setGenerator(PchGeneratorInterface *pchGenerator); - -unittest_public: - Utils::PathStringVector generateGlobalHeaderPaths() const; - Utils::PathStringVector generateGlobalSourcePaths() const; - Utils::PathStringVector generateGlobalHeaderAndSourcePaths() const; - Utils::SmallStringVector generateGlobalArguments() const; - Utils::SmallStringVector generateGlobalCommandLine() const; - Utils::SmallStringVector generateGlobalPchCompilerArguments() const; - Utils::SmallStringVector generateGlobalClangCompilerArguments() const; - - FilePathIds generateGlobalPchIncludeIds() const; + const IdPaths &projectIncludes() const; + const FilePathCaching &filePathCache(); Utils::SmallString generatePchIncludeFileContent(const FilePathIds &includeIds) const; - Utils::SmallString generateGlobalPchHeaderFileContent() const; - std::unique_ptr generateGlobalPchHeaderFile(); - void generatePch(Utils::SmallStringVector &&commandLineArguments, - ProjectPartPch &&projectPartPch); - void generateGlobalPch(); - - Utils::SmallString globalPchContent() const; + bool generatePch(Utils::SmallStringVector &&commandLineArguments); static QStringList convertToQStringList(const Utils::SmallStringVector &convertToQStringList); - Utils::SmallString generateGlobalPchFilePathWithoutExtension() const; - Utils::SmallString generateGlobalPchHeaderFilePath() const; - Utils::SmallString generateGlobalPchFilePath() const; - Utils::SmallStringVector generateProjectPartCommandLine( const V2::ProjectPartContainer &projectPart) const; Utils::SmallString generateProjectPartPchFilePathWithoutExtension( @@ -116,20 +105,18 @@ unittest_public: const Utils::SmallString &filePath, const Utils::SmallString &content); - void generatePchs(); - private: static QByteArray projectPartHash(const V2::ProjectPartContainer &projectPart); - QByteArray globalProjectHash() const; private: - V2::ProjectPartContainers m_projectParts; - std::vector m_projectPartPchs; - std::vector m_projectsIncludeIds; - const GeneratedFiles &m_generatedFiles; + ProjectPartPch m_projectPartPch; + IdPaths m_projectIncludeIds; + FilePathCaching m_filePathCache; + V2::FileContainers m_unsavedFiles; Environment &m_environment; - FilePathCachingInterface &m_filePathCache; - PchGeneratorInterface *m_pchGenerator = nullptr; + PchManagerClientInterface &m_pchManagerClient; + ClangPathWatcherInterface &m_fileSystemWatcher; + bool m_isUsed = false; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h b/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h index dd33176519d..c3098577f70 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h @@ -27,21 +27,23 @@ #include "idpaths.h" #include "projectpartpch.h" +#include "processorinterface.h" #include #include namespace ClangBackEnd { -class PchCreatorInterface +class PchCreatorInterface : public ProcessorInterface { public: PchCreatorInterface() = default; PchCreatorInterface(const PchCreatorInterface &) = delete; PchCreatorInterface &operator=(const PchCreatorInterface &) = delete; - virtual void generatePchs(V2::ProjectPartContainers &&projectsParts) = 0; - virtual std::vector takeProjectsIncludes() = 0; + virtual void generatePch(const V2::ProjectPartContainer &projectsPart) = 0; + virtual IdPaths takeProjectIncludes() = 0; + virtual const ProjectPartPch &projectPartPch() = 0; protected: ~PchCreatorInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/pchgenerator.h b/src/tools/clangpchmanagerbackend/source/pchgenerator.h deleted file mode 100644 index 144f21bffa8..00000000000 --- a/src/tools/clangpchmanagerbackend/source/pchgenerator.h +++ /dev/null @@ -1,165 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 "environment.h" -#include "pchgeneratorinterface.h" -#include "pchgeneratornotifierinterface.h" - -#include - -#include - -#include - -namespace ClangBackEnd { - -template -class PchGenerator final : public PchGeneratorInterface -{ -public: - PchGenerator(Environment &environment, - PchGeneratorNotifierInterface *notifier=nullptr) - : m_environment(environment), - m_notifier(notifier) - { - } - - ~PchGenerator() - { - cleanupAllProcesses(); - } - - void startTask(Utils::SmallStringVector &&compilerArguments, ProjectPartPch &&projectPartPch) override - { - addTask(std::move(compilerArguments), std::move(projectPartPch)); - } - - void setNotifier(PchGeneratorNotifierInterface *notifier) - { - m_notifier = notifier; - } - -unittest_public: - Process *addTask(Utils::SmallStringVector &&compilerArguments, ProjectPartPch &&projectPartPch) - { - auto process = std::make_unique(); - Process *processPointer = process.get(); - - process->setProcessChannelMode(QProcess::ForwardedChannels); - process->setArguments(QStringList(compilerArguments)); - process->setProgram(QString(m_environment.clangCompilerPath())); - - connectProcess(processPointer, std::move(projectPartPch)); - - if (!deferProcess()) - startProcess(std::move(process)); - else - m_deferredProcesses.push(std::move(process)); - - return processPointer; - } - - void connectProcess(Process *process, ProjectPartPch &&projectPartPch) - { - auto finishedCallback = [=,projectPartPch=std::move(projectPartPch)] (int exitCode, QProcess::ExitStatus exitStatus) { - deleteProcess(process); - activateNextDeferredProcess(); - m_notifier->taskFinished(generateTaskFinishStatus(exitCode, exitStatus), projectPartPch); - }; - - QObject::connect(process, - static_cast(&Process::finished), - std::move(finishedCallback)); - } - - void startProcess(std::unique_ptr &&process) - { - process->start(); - m_runningProcesses.push_back(std::move(process)); - } - - const std::vector> &runningProcesses() const - { - return m_runningProcesses; - } - - const std::queue> &deferredProcesses() const - { - return m_deferredProcesses; - } - - void deleteProcess(Process *process) - { - auto found = std::find_if(m_runningProcesses.begin(), - m_runningProcesses.end(), - [=] (const std::unique_ptr &entry) { - return entry.get() == process; - }); - - if (found != m_runningProcesses.end()) { - std::unique_ptr avoidDoubleDeletedProcess = std::move(*found); - m_runningProcesses.erase(found); - } - } - - void cleanupAllProcesses() - { - std::vector> runningProcesses = std::move(m_runningProcesses); - std::queue> deferredProcesses = std::move(m_deferredProcesses); - } - - static TaskFinishStatus generateTaskFinishStatus(int exitCode, QProcess::ExitStatus exitStatus) - { - if (exitCode != 0 || exitStatus != QProcess::NormalExit) - return TaskFinishStatus::Unsuccessfully; - else - return TaskFinishStatus::Successfully; - } - - bool deferProcess() const - { - return m_environment.hardwareConcurrency() <= m_runningProcesses.size(); - } - - void activateNextDeferredProcess() - { - if (!m_deferredProcesses.empty()) { - std::unique_ptr process = std::move(m_deferredProcesses.front()); - m_deferredProcesses.pop(); - - startProcess(std::move(process)); - } - } - -private: - std::vector> m_runningProcesses; - std::queue> m_deferredProcesses; - Environment &m_environment; - PchGeneratorNotifierInterface *m_notifier=nullptr; -}; - -} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.h b/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.h deleted file mode 100644 index 32f47c9f5cb..00000000000 --- a/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.h +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 - -namespace ClangBackEnd { - -class ProjectPartPch; - -enum class TaskFinishStatus -{ - Successfully, - Unsuccessfully -}; - -class PchGeneratorNotifierInterface -{ -public: - PchGeneratorNotifierInterface() = default; - PchGeneratorNotifierInterface(const PchGeneratorNotifierInterface &) = delete; - PchGeneratorNotifierInterface &operator=(const PchGeneratorNotifierInterface &) = delete; - - virtual void taskFinished(TaskFinishStatus status, const ProjectPartPch &projectPartPch) = 0; - -protected: - ~PchGeneratorNotifierInterface() = default; -}; - -} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp index e165365d303..7ce2e553a2c 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -39,11 +40,11 @@ namespace ClangBackEnd { PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, - PchCreatorInterface &pchCreator, + ProjectPartQueueInterface &projectPartQueue, ProjectPartsInterface &projectParts, GeneratedFilesInterface &generatedFiles) : m_fileSystemWatcher(fileSystemWatcher), - m_pchCreator(pchCreator), + m_projectPartQueue(projectPartQueue), m_projectParts(projectParts), m_generatedFiles(generatedFiles) { @@ -58,9 +59,7 @@ void PchManagerServer::end() void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message) { - m_pchCreator.generatePchs(m_projectParts.update(message.takeProjectsParts())); - - m_fileSystemWatcher.updateIdPaths(m_pchCreator.takeProjectsIncludes()); + m_projectPartQueue.addProjectParts(m_projectParts.update(message.takeProjectsParts())); } void PchManagerServer::removeProjectParts(RemoveProjectPartsMessage &&message) @@ -68,6 +67,8 @@ void PchManagerServer::removeProjectParts(RemoveProjectPartsMessage &&message) m_fileSystemWatcher.removeIds(message.projectsPartIds); m_projectParts.remove(message.projectsPartIds); + + m_projectPartQueue.removeProjectParts(message.projectsPartIds); } void PchManagerServer::updateGeneratedFiles(UpdateGeneratedFilesMessage &&message) @@ -82,19 +83,11 @@ void PchManagerServer::removeGeneratedFiles(RemoveGeneratedFilesMessage &&messag void PchManagerServer::pathsWithIdsChanged(const Utils::SmallStringVector &ids) { - m_pchCreator.generatePchs(m_projectParts.projects(ids)); - - m_fileSystemWatcher.updateIdPaths(m_pchCreator.takeProjectsIncludes()); + m_projectPartQueue.addProjectParts(m_projectParts.projects(ids)); } void PchManagerServer::pathsChanged(const FilePathIds &/*filePathIds*/) { } -void PchManagerServer::taskFinished(TaskFinishStatus status, const ProjectPartPch &projectPartPch) -{ - if (status == TaskFinishStatus::Successfully) - client()->precompiledHeadersUpdated(PrecompiledHeadersUpdatedMessage({projectPartPch.clone()})); -} - } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h index 717ba033590..66b6c85e991 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h @@ -28,7 +28,6 @@ #include "clangpathwatcherinterface.h" #include "clangpathwatchernotifier.h" #include "pchcreatorinterface.h" -#include "pchgeneratornotifierinterface.h" #include "pchmanagerserverinterface.h" #include "projectpartsinterface.h" @@ -38,16 +37,16 @@ namespace ClangBackEnd { class SourceRangesAndDiagnosticsForQueryMessage; +class ProjectPartQueueInterface; class PchManagerServer : public PchManagerServerInterface, public ClangPathWatcherNotifier, - public PchGeneratorNotifierInterface, public IpcClientProvider { public: PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, - PchCreatorInterface &pchCreator, + ProjectPartQueueInterface &projectPartQueue, ProjectPartsInterface &projectParts, GeneratedFilesInterface &generatedFiles); @@ -59,11 +58,10 @@ public: void pathsWithIdsChanged(const Utils::SmallStringVector &ids) override; void pathsChanged(const FilePathIds &filePathIds) override; - void taskFinished(TaskFinishStatus status, const ProjectPartPch &projectPartPch) override; private: ClangPathWatcherInterface &m_fileSystemWatcher; - PchCreatorInterface &m_pchCreator; + ProjectPartQueueInterface &m_projectPartQueue; ProjectPartsInterface &m_projectParts; GeneratedFilesInterface &m_generatedFiles; }; diff --git a/src/plugins/clangpchmanager/precompiledheaderstorage.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h similarity index 99% rename from src/plugins/clangpchmanager/precompiledheaderstorage.h rename to src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h index 4ad57e980a5..94c454231ee 100644 --- a/src/plugins/clangpchmanager/precompiledheaderstorage.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h @@ -32,7 +32,7 @@ #include -namespace ClangPchManager { +namespace ClangBackEnd { template class PrecompiledHeaderStorage final : public PrecompiledHeaderStorageInterface diff --git a/src/plugins/clangpchmanager/precompiledheaderstorageinterface.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h similarity index 97% rename from src/plugins/clangpchmanager/precompiledheaderstorageinterface.h rename to src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h index 1c834acbd35..9ff6e1efe28 100644 --- a/src/plugins/clangpchmanager/precompiledheaderstorageinterface.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h @@ -27,7 +27,7 @@ #include -namespace ClangPchManager { +namespace ClangBackEnd { class PrecompiledHeaderStorageInterface { @@ -47,4 +47,4 @@ protected: ~PrecompiledHeaderStorageInterface() = default; }; -} // namespace ClangPchManager +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/processorinterface.h b/src/tools/clangpchmanagerbackend/source/processorinterface.h new file mode 100644 index 00000000000..444c6c6ddb5 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/processorinterface.h @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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 + +namespace ClangBackEnd { + +class ProcessorInterface +{ +public: + ProcessorInterface() = default; + virtual ~ProcessorInterface() = default; + ProcessorInterface(const ProcessorInterface &) = delete; + ProcessorInterface &operator=(const ProcessorInterface &) = delete; + + virtual void setUnsavedFiles(const V2::FileContainers &unsavedFiles) = 0; + virtual bool isUsed() const = 0; + virtual void setIsUsed(bool isUsed) = 0; + virtual void clear() = 0; + virtual void doInMainThreadAfterFinished() = 0; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolscollectormanager.h b/src/tools/clangpchmanagerbackend/source/processormanager.h similarity index 58% rename from src/tools/clangrefactoringbackend/source/symbolscollectormanager.h rename to src/tools/clangpchmanagerbackend/source/processormanager.h index d5a020904f2..be20c5d87fb 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollectormanager.h +++ b/src/tools/clangpchmanagerbackend/source/processormanager.h @@ -25,8 +25,8 @@ #pragma once -#include "symbolscollectormanagerinterface.h" -#include "symbolscollectorinterface.h" + +#include "processormanagerinterface.h" #include "generatedfiles.h" #include @@ -38,51 +38,54 @@ class Database; namespace ClangBackEnd { class GeneratedFiles; -class SymbolsCollector; -template -class SymbolsCollectorManager final : public SymbolsCollectorManagerInterface + +template +class ProcessorManager : public ProcessorManagerInterface { public: - SymbolsCollectorManager(Sqlite::Database &database, - const GeneratedFiles &generatedFiles) - : m_database(database), - m_generatedFiles(generatedFiles) + using Processor = ProcessorType; + ProcessorManager(const GeneratedFiles &generatedFiles) + : m_generatedFiles(generatedFiles) {} - SymbolsCollector &unusedSymbolsCollector() override + Processor &unusedProcessor() override { - auto split = std::partition(m_collectors.begin(), - m_collectors.end(), + auto split = std::partition(m_processors.begin(), + m_processors.end(), [] (const auto &collector) { return collector->isUsed(); }); - auto freeCollectors = std::distance(split, m_collectors.end()); + auto freeCollectors = std::distance(split, m_processors.end()); if (freeCollectors > 0) return initializedCollector(*split->get()); - m_collectors.emplace_back(std::make_unique(m_database)); + m_processors.push_back(createProcessor()); - return initializedCollector(*m_collectors.back().get()); + return initializedCollector(*m_processors.back().get()); } - const std::vector> &collectors() const + const std::vector> &processors() const { - return m_collectors; + return m_processors; } +protected: + ~ProcessorManager() = default; + virtual std::unique_ptr createProcessor() const = 0; + private: - SymbolsCollector &initializedCollector(SymbolsCollector &collector) + Processor &initializedCollector(Processor &creator) { - collector.setIsUsed(true); - collector.setUnsavedFiles(m_generatedFiles.fileContainers()); - return collector; + creator.setIsUsed(true); + creator.setUnsavedFiles(m_generatedFiles.fileContainers()); + return creator; } + private: - std::vector> m_collectors; - Sqlite::Database &m_database; + std::vector> m_processors; const GeneratedFiles &m_generatedFiles; }; diff --git a/src/tools/clangrefactoringbackend/source/symbolscollectormanagerinterface.h b/src/tools/clangpchmanagerbackend/source/processormanagerinterface.h similarity index 74% rename from src/tools/clangrefactoringbackend/source/symbolscollectormanagerinterface.h rename to src/tools/clangpchmanagerbackend/source/processormanagerinterface.h index b0cb3a03328..13d02fbc94b 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollectormanagerinterface.h +++ b/src/tools/clangpchmanagerbackend/source/processormanagerinterface.h @@ -25,25 +25,23 @@ #pragma once -#include +#include -#include +#include namespace ClangBackEnd { -class SymbolsCollectorInterface; - -class SymbolsCollectorManagerInterface +class ProcessorManagerInterface { public: - SymbolsCollectorManagerInterface() = default; - SymbolsCollectorManagerInterface(const SymbolsCollectorManagerInterface &) = delete; - SymbolsCollectorManagerInterface &operator=(const SymbolsCollectorManagerInterface &) = delete; + ProcessorManagerInterface() = default; + ProcessorManagerInterface(const ProcessorManagerInterface &) = delete; + ProcessorManagerInterface &operator=(const ProcessorManagerInterface &) = delete; - virtual SymbolsCollectorInterface &unusedSymbolsCollector() = 0; + virtual ProcessorInterface &unusedProcessor() = 0; protected: - ~SymbolsCollectorManagerInterface() = default; + ~ProcessorManagerInterface() = default; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/projectpartqueue.cpp b/src/tools/clangpchmanagerbackend/source/projectpartqueue.cpp new file mode 100644 index 00000000000..e61913ac04a --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/projectpartqueue.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** 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 "projectpartqueue.h" + +#include +#include +#include + +namespace ClangBackEnd { + +void ProjectPartQueue::addProjectParts(V2::ProjectPartContainers &&projectParts) +{ + auto compare = [](const V2::ProjectPartContainer &first, const V2::ProjectPartContainer &second) { + return first.projectPartId < second.projectPartId; + }; + + V2::ProjectPartContainers mergedProjectParts; + mergedProjectParts.reserve(m_projectParts.size() + projectParts.size()); + std::set_union(std::make_move_iterator(projectParts.begin()), + std::make_move_iterator(projectParts.end()), + std::make_move_iterator(m_projectParts.begin()), + std::make_move_iterator(m_projectParts.end()), + std::back_inserter(mergedProjectParts), + compare); + + m_projectParts = std::move(mergedProjectParts); +} + +class CompareDifference +{ +public: + bool operator()(const V2::ProjectPartContainer &first, const Utils::SmallString &second) + { + return first.projectPartId < second; + } + + bool operator()(const Utils::SmallString &first, const V2::ProjectPartContainer &second) + { + return first < second.projectPartId; + } +}; + +void ProjectPartQueue::removeProjectParts(const Utils::SmallStringVector &projectsPartIds) +{ + V2::ProjectPartContainers notToBeRemovedProjectParts; + notToBeRemovedProjectParts.reserve(m_projectParts.size()); + std::set_difference(std::make_move_iterator(m_projectParts.begin()), + std::make_move_iterator(m_projectParts.end()), + projectsPartIds.begin(), + projectsPartIds.end(), + std::back_inserter(notToBeRemovedProjectParts), + CompareDifference{}); + + m_projectParts = std::move(notToBeRemovedProjectParts); +} + +void ProjectPartQueue::processEntries() +{ + uint taskCount = m_taskScheduler.freeSlots(); + + auto newEnd = std::prev(m_projectParts.end(), std::min(int(taskCount), int(m_projectParts.size()))); + m_taskScheduler.addTasks( + createPchTasks({std::make_move_iterator(newEnd), + std::make_move_iterator(m_projectParts.end())})); + m_projectParts.erase(newEnd, m_projectParts.end()); +} + +const V2::ProjectPartContainers &ProjectPartQueue::projectParts() const +{ + return m_projectParts; +} + +std::vector ProjectPartQueue::createPchTasks( + V2::ProjectPartContainers &&projectParts) const +{ + std::vector tasks; + tasks.reserve(projectParts.size()); + + auto convert = [this] (auto &&projectPart) { + return [projectPart=std::move(projectPart), this] (PchCreatorInterface &pchCreator) { + pchCreator.generatePch(projectPart); + const auto &projectPartPch = pchCreator.projectPartPch(); + Sqlite::ImmediateTransaction transaction(m_transactionsInterface); + if (projectPartPch.pchPath.empty()) { + m_precompiledHeaderStorage.deletePrecompiledHeader(projectPartPch.projectPartId); + } else { + m_precompiledHeaderStorage.insertPrecompiledHeader(projectPartPch.projectPartId, + projectPartPch.pchPath, + projectPartPch.lastModified); + } + transaction.commit(); + }; + }; + + std::transform(std::make_move_iterator(projectParts.begin()), + std::make_move_iterator(projectParts.end()), + std::back_inserter(tasks), + convert); + + return tasks; +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskschedulerinterface.h b/src/tools/clangpchmanagerbackend/source/projectpartqueue.h similarity index 51% rename from src/tools/clangrefactoringbackend/source/symbolindexertaskschedulerinterface.h rename to src/tools/clangpchmanagerbackend/source/projectpartqueue.h index c71454df3d8..55b490fc644 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskschedulerinterface.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartqueue.h @@ -25,8 +25,8 @@ #pragma once -#include -#include +#include "projectpartqueueinterface.h" +#include "taskschedulerinterface.h" namespace Sqlite { class TransactionInterface; @@ -34,27 +34,37 @@ class TransactionInterface; namespace ClangBackEnd { -class SymbolsCollectorInterface; -class SymbolStorageInterface; +class PrecompiledHeaderStorageInterface; +class PchTaskSchedulerInterface; +class PchCreatorInterface; -using uint = unsigned int; - -class SymbolIndexerTaskSchedulerInterface +class ProjectPartQueue final : public ProjectPartQueueInterface { public: - using Task = std::function; + using Task = std::function; - SymbolIndexerTaskSchedulerInterface() = default; - SymbolIndexerTaskSchedulerInterface(const SymbolIndexerTaskSchedulerInterface &) = delete; - SymbolIndexerTaskSchedulerInterface &operator=(const SymbolIndexerTaskSchedulerInterface &) = delete; + ProjectPartQueue(TaskSchedulerInterface &taskScheduler, + PrecompiledHeaderStorageInterface &precompiledHeaderStorage, + Sqlite::TransactionInterface &transactionsInterface) + : m_taskScheduler(taskScheduler), + m_precompiledHeaderStorage(precompiledHeaderStorage), + m_transactionsInterface(transactionsInterface) + {} - virtual void addTasks(std::vector &&tasks) = 0; - virtual uint freeSlots() = 0; + void addProjectParts(V2::ProjectPartContainers &&projectParts); + void removeProjectParts(const Utils::SmallStringVector &projectsPartIds); -protected: - ~SymbolIndexerTaskSchedulerInterface() = default; + void processEntries(); + + const V2::ProjectPartContainers &projectParts() const; + + std::vector createPchTasks(V2::ProjectPartContainers &&projectParts) const; + +private: + V2::ProjectPartContainers m_projectParts; + TaskSchedulerInterface &m_taskScheduler; + PrecompiledHeaderStorageInterface &m_precompiledHeaderStorage; + Sqlite::TransactionInterface &m_transactionsInterface; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/projectpartqueueinterface.h b/src/tools/clangpchmanagerbackend/source/projectpartqueueinterface.h new file mode 100644 index 00000000000..0b705fe3129 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/projectpartqueueinterface.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** 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 "queueinterface.h" + +#include + +namespace ClangBackEnd { + +class ProjectPartQueueInterface : public QueueInterface +{ +public: + virtual void addProjectParts(V2::ProjectPartContainers &&projectParts) = 0; + virtual void removeProjectParts(const Utils::SmallStringVector &projectsPartIds) = 0; + +protected: + ~ProjectPartQueueInterface() = default; +}; +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.cpp b/src/tools/clangpchmanagerbackend/source/projectparts.cpp index b1689f036d6..6be06380bfd 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.cpp +++ b/src/tools/clangpchmanagerbackend/source/projectparts.cpp @@ -35,9 +35,7 @@ inline namespace Pch { V2::ProjectPartContainers ProjectParts::update(V2::ProjectPartContainers &&projectsParts) { - auto uniqueProjectParts = ProjectParts::uniqueProjectParts(std::move(projectsParts)); - - auto updatedProjectPartContainers = newProjectParts(std::move(uniqueProjectParts)); + auto updatedProjectPartContainers = newProjectParts(std::move(projectsParts)); mergeProjectParts(updatedProjectPartContainers); @@ -68,16 +66,6 @@ V2::ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector return projectPartsWithIds; } -V2::ProjectPartContainers ProjectParts::uniqueProjectParts(V2::ProjectPartContainers &&projectsParts) -{ - std::sort(projectsParts.begin(), projectsParts.end()); - auto newEnd = std::unique(projectsParts.begin(), projectsParts.end()); - - projectsParts.erase(newEnd, projectsParts.end()); - - return std::move(projectsParts); -} - V2::ProjectPartContainers ProjectParts::newProjectParts(V2::ProjectPartContainers &&projectsParts) const { V2::ProjectPartContainers updatedProjectPartContainers; diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.h b/src/tools/clangpchmanagerbackend/source/projectparts.h index 67c8bc02563..c0d9c61e7fb 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.h +++ b/src/tools/clangpchmanagerbackend/source/projectparts.h @@ -43,7 +43,6 @@ public: V2::ProjectPartContainers projects(const Utils::SmallStringVector &projectPartIds) const override; unittest_public: - static V2::ProjectPartContainers uniqueProjectParts(V2::ProjectPartContainers &&projectsParts); V2::ProjectPartContainers newProjectParts(V2::ProjectPartContainers &&projectsParts) const; void mergeProjectParts(const V2::ProjectPartContainers &projectsParts); const V2::ProjectPartContainers &projectParts() const; diff --git a/src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.h b/src/tools/clangpchmanagerbackend/source/queueinterface.h similarity index 73% rename from src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.h rename to src/tools/clangpchmanagerbackend/source/queueinterface.h index c25eb248b20..d8ec0c69ed9 100644 --- a/src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.h +++ b/src/tools/clangpchmanagerbackend/source/queueinterface.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -29,21 +29,16 @@ namespace ClangBackEnd { -class ProjectPartPch; - -class PchGeneratorInterface +class QueueInterface { public: - PchGeneratorInterface() = default; - PchGeneratorInterface(const PchGeneratorInterface &) = delete; - PchGeneratorInterface &operator=(const PchGeneratorInterface &) = delete; + QueueInterface() = default; + QueueInterface(const QueueInterface &) = delete; + QueueInterface &operator=(const QueueInterface &) = delete; - virtual void startTask(Utils::SmallStringVector &&compilerArguments, - ProjectPartPch &&projectPartPch) = 0; + virtual void processEntries() = 0; protected: - ~PchGeneratorInterface() = default; + ~QueueInterface() = default; }; - } // namespace ClangBackEnd - diff --git a/src/tools/clangpchmanagerbackend/source/taskscheduler.h b/src/tools/clangpchmanagerbackend/source/taskscheduler.h new file mode 100644 index 00000000000..35c3c519843 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/taskscheduler.h @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** 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 "taskschedulerinterface.h" +#include "symbolindexertask.h" +#include "queueinterface.h" + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace Sqlite { +class TransactionInterface; +}; + +namespace ClangBackEnd { + +class FilePathCachingInterface; +class ProcessorManagerInterface; +class QueueInterface; +class SymbolStorageInterface; + +template +class TaskScheduler : public TaskSchedulerInterface +{ +public: + using ProcessorInterface = typename ProcessorManager::Processor; + using Future = std::future; + + TaskScheduler(ProcessorManager &symbolsCollectorManager, + QueueInterface &queue, + uint hardwareConcurrency, + std::launch launchPolicy = std::launch::async) + : m_processorManager(symbolsCollectorManager), + m_queue(queue), + m_hardwareConcurrency(hardwareConcurrency), + m_launchPolicy(launchPolicy) + {} + + void addTasks(std::vector &&tasks) + { + for (auto &task : tasks) { + auto callWrapper = [&, task=std::move(task)] (auto processor) + -> ProcessorInterface& { + task(processor.get()); + executeInLoop([&] { + m_queue.processEntries(); + }); + + return processor; + }; + m_futures.emplace_back(std::async(m_launchPolicy, + std::move(callWrapper), + std::ref(m_processorManager.unusedProcessor()))); + } + } + + const std::vector &futures() const + { + return m_futures; + } + + uint freeSlots() + { + removeFinishedFutures(); + + if (m_isDisabled) + return 0; + + return uint(std::max(int(m_hardwareConcurrency) - int(m_futures.size()), 0)); + } + + void syncTasks() + { + for (auto &future : m_futures) + future.wait(); + } + + void disable() + { + m_isDisabled = true; + } + +private: + void removeFinishedFutures() + { + auto notReady = [] (Future &future) { + return future.wait_for(std::chrono::duration::zero()) != std::future_status::ready; + }; + + auto split = std::partition(m_futures.begin(), m_futures.end(), notReady); + + std::for_each(split, m_futures.end(), [] (Future &future) { + ProcessorInterface &processor = future.get(); + processor.doInMainThreadAfterFinished(); + processor.setIsUsed(false); + processor.clear(); + }); + + m_futures.erase(split, m_futures.end()); + } + + #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) + template + class CallableEvent : public QEvent { + public: + using Callable = std::decay_t; + CallableEvent(Callable &&callable) + : QEvent(QEvent::None), + callable(std::move(callable)) + {} + CallableEvent(const Callable &callable) + : QEvent(QEvent::None), + callable(callable) + {} + + ~CallableEvent() + { + callable(); + } + public: + Callable callable; + }; + + template + void executeInLoop(Callable &&callable, QObject *object = QCoreApplication::instance()) { + if (QThread *thread = qobject_cast(object)) + object = QAbstractEventDispatcher::instance(thread); + + QCoreApplication::postEvent(object, + new CallableEvent(std::forward(callable)), + Qt::HighEventPriority); + } + #else + template + void executeInLoop(Callable &&callable, QObject *object = QCoreApplication::instance()) { + if (QThread *thread = qobject_cast(object)) + object = QAbstractEventDispatcher::instance(thread); + + QMetaObject::invokeMethod(object, std::forward(callable)); + } + #endif + +private: + std::vector m_futures; + ProcessorManager &m_processorManager; + QueueInterface &m_queue; + uint m_hardwareConcurrency; + std::launch m_launchPolicy; + bool m_isDisabled = false; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/taskschedulerinterface.h b/src/tools/clangpchmanagerbackend/source/taskschedulerinterface.h new file mode 100644 index 00000000000..a79a3ed8d2c --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/taskschedulerinterface.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** 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 + +namespace ClangBackEnd { + +using uint = unsigned int; + +template +class TaskSchedulerInterface +{ +public: + TaskSchedulerInterface() = default; + TaskSchedulerInterface(const TaskSchedulerInterface &) = delete; + TaskSchedulerInterface &operator=(const TaskSchedulerInterface &) = delete; + + virtual void addTasks(std::vector &&tasks) = 0; + virtual uint freeSlots() = 0; + +protected: + ~TaskSchedulerInterface() = default; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/clangrefactoringbackend.pro b/src/tools/clangrefactoringbackend/clangrefactoringbackend.pro index 072d2547280..ea66a43b61e 100644 --- a/src/tools/clangrefactoringbackend/clangrefactoringbackend.pro +++ b/src/tools/clangrefactoringbackend/clangrefactoringbackend.pro @@ -17,6 +17,7 @@ QT -= gui LIBS += $$LIBTOOLING_LIBS INCLUDEPATH += $$LLVM_INCLUDEPATH +INCLUDEPATH += ../clangpchmanagerbackend/source QMAKE_CXXFLAGS += $$LLVM_CXXFLAGS diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri index d15e0f625dc..26fa44aa683 100644 --- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri +++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri @@ -24,11 +24,7 @@ HEADERS += \ $$PWD/indexdataconsumer.h \ $$PWD/sourcesmanager.h \ $$PWD/symbolindexertaskqueue.h \ - $$PWD/symbolindexertaskscheduler.h \ - $$PWD/symbolscollectormanagerinterface.h \ $$PWD/symbolindexertaskqueueinterface.h \ - $$PWD/symbolindexertaskschedulerinterface.h \ - $$PWD/symbolscollectormanager.h \ $$PWD/symbolindexertask.h !isEmpty(LIBTOOLING_LIBS) { @@ -74,6 +70,4 @@ SOURCES += \ $$PWD/sourcerangefilter.cpp \ $$PWD/symbolindexer.cpp \ $$PWD/projectpartartefact.cpp \ - $$PWD/filestatuscache.cpp \ - $$PWD/symbolindexertaskqueue.cpp \ - $$PWD/symbolindexertaskscheduler.cpp + $$PWD/filestatuscache.cpp diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp index 5c9f0cbcccb..272e89fa892 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp @@ -101,27 +101,25 @@ void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart) std::vector symbolIndexerTask; symbolIndexerTask.reserve(projectPart.sourcePathIds.size()); for (FilePathId sourcePathId : projectPart.sourcePathIds) { - auto indexing = [projectPartId, arguments, sourcePathId] - (SymbolsCollectorInterface &symbolsCollector, - SymbolStorageInterface &symbolStorage, - Sqlite::TransactionInterface &transactionInterface) { + auto indexing = [projectPartId, arguments, sourcePathId, this] + (SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(sourcePathId, arguments); symbolsCollector.collectSymbols(); - Sqlite::ImmediateTransaction transaction{transactionInterface}; + Sqlite::ImmediateTransaction transaction{m_transactionInterface}; - symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), - symbolsCollector.sourceLocations()); + m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), + symbolsCollector.sourceLocations()); - symbolStorage.updateProjectPartSources(projectPartId, - symbolsCollector.sourceFiles()); + m_symbolStorage.updateProjectPartSources(projectPartId, + symbolsCollector.sourceFiles()); - symbolStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); + m_symbolStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - symbolStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_symbolStorage.insertFileStatuses(symbolsCollector.fileStatuses()); - symbolStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies()); + m_symbolStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies()); transaction.commit(); }; @@ -130,7 +128,7 @@ void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart) } m_symbolIndexerTaskQueue.addOrUpdateTasks(std::move(symbolIndexerTask)); - m_symbolIndexerTaskQueue.processTasks(); + m_symbolIndexerTaskQueue.processEntries(); } void SymbolIndexer::pathsWithIdsChanged(const Utils::SmallStringVector &) @@ -146,7 +144,7 @@ void SymbolIndexer::pathsChanged(const FilePathIds &filePathIds) updateChangedPath(filePathId, symbolIndexerTask); m_symbolIndexerTaskQueue.addOrUpdateTasks(std::move(symbolIndexerTask)); - m_symbolIndexerTaskQueue.processTasks(); + m_symbolIndexerTaskQueue.processEntries(); } void SymbolIndexer::updateChangedPath(FilePathId filePathId, @@ -169,26 +167,24 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, const Utils::SmallStringVector arguments = compilerArguments(artefact.compilerArguments, optionalProjectPartPch); - auto indexing = [projectPartId=artefact.projectPartId, arguments, filePathId] - (SymbolsCollectorInterface &symbolsCollector, - SymbolStorageInterface &symbolStorage, - Sqlite::TransactionInterface &transactionInterface) { + auto indexing = [projectPartId=artefact.projectPartId, arguments, filePathId, this] + (SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(filePathId, arguments); symbolsCollector.collectSymbols(); - Sqlite::ImmediateTransaction transaction{transactionInterface}; + Sqlite::ImmediateTransaction transaction{m_transactionInterface}; - symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), - symbolsCollector.sourceLocations()); + m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), + symbolsCollector.sourceLocations()); - symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles()); + m_symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles()); - symbolStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); + m_symbolStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - symbolStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_symbolStorage.insertFileStatuses(symbolsCollector.fileStatuses()); - symbolStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies()); + m_symbolStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies()); transaction.commit(); }; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertask.h b/src/tools/clangrefactoringbackend/source/symbolindexertask.h index 3b18681e072..de3303815d2 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertask.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexertask.h @@ -35,16 +35,13 @@ class TransactionInterface; namespace ClangBackEnd { -class SymbolIndexerTaskSchedulerInterface; class SymbolsCollectorInterface; class SymbolStorageInterface; class SymbolIndexerTask { public: - using Callable = std::function; + using Callable = std::function; SymbolIndexerTask(FilePathId filePathId, int projectPartId, diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp deleted file mode 100644 index bb891467a67..00000000000 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.cpp +++ /dev/null @@ -1,71 +0,0 @@ -/**************************************************************************** -** -** 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 "symbolindexertaskqueue.h" - -#include - -#include - -namespace ClangBackEnd { - -void SymbolIndexerTaskQueue::addOrUpdateTasks(std::vector &&tasks) -{ - auto merge = [] (SymbolIndexerTask &&first, SymbolIndexerTask &&second) { - first.callable = std::move(second.callable); - - return std::move(first); - }; - - m_tasks = Utils::setUnionMerge>(tasks, m_tasks, merge); -} - -void SymbolIndexerTaskQueue::removeTasks(const std::vector &projectPartIds) -{ - auto shouldBeRemoved = [&] (const SymbolIndexerTask& task) { - return std::binary_search(projectPartIds.begin(), projectPartIds.end(), task.projectPartId); - }; - - auto newEnd = std::remove_if(m_tasks.begin(), m_tasks.end(), shouldBeRemoved); - - m_tasks.erase(newEnd, m_tasks.end()); -} - -const std::vector &SymbolIndexerTaskQueue::tasks() const -{ - return m_tasks; -} - -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 6a627e8865f..3dc54998d03 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueue.h @@ -29,7 +29,9 @@ #include "symbolindexertask.h" #include +#include +#include #include #include @@ -41,29 +43,59 @@ class TransactionInterface; namespace ClangBackEnd { -class SymbolIndexerTaskSchedulerInterface; class SymbolsCollectorInterface; class SymbolStorageInterface; class SymbolIndexerTaskQueue final : public SymbolIndexerTaskQueueInterface { public: - SymbolIndexerTaskQueue(SymbolIndexerTaskSchedulerInterface &symbolIndexerTaskScheduler) + using Task = SymbolIndexerTask::Callable; + + SymbolIndexerTaskQueue(TaskSchedulerInterface &symbolIndexerTaskScheduler) : m_symbolIndexerScheduler(symbolIndexerTaskScheduler) {} - void addOrUpdateTasks(std::vector &&tasks); - void removeTasks(const std::vector &projectPartIds); + void addOrUpdateTasks(std::vector &&tasks) + { + auto merge = [] (SymbolIndexerTask &&first, SymbolIndexerTask &&second) { + first.callable = std::move(second.callable); - const std::vector &tasks() const; + return std::move(first); + }; - void processTasks(); + m_tasks = Utils::setUnionMerge>(tasks, m_tasks, merge); + } + void removeTasks(const std::vector &projectPartIds) + { + auto shouldBeRemoved = [&] (const SymbolIndexerTask& task) { + return std::binary_search(projectPartIds.begin(), projectPartIds.end(), task.projectPartId); + }; + + auto newEnd = std::remove_if(m_tasks.begin(), m_tasks.end(), shouldBeRemoved); + + m_tasks.erase(newEnd, m_tasks.end()); + } + + const std::vector &tasks() const + { + return m_tasks; + } + + void processEntries() + { + uint taskCount = m_symbolIndexerScheduler.freeSlots(); + + auto newEnd = std::prev(m_tasks.end(), std::min(int(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()); + } void syncTasks(); private: std::vector m_projectPartIds; std::vector m_tasks; - SymbolIndexerTaskSchedulerInterface &m_symbolIndexerScheduler; + TaskSchedulerInterface &m_symbolIndexerScheduler; }; } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h index 9e96a79e6c8..dfcc78bd235 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexertaskqueueinterface.h @@ -25,24 +25,21 @@ #pragma once +#include + #include namespace ClangBackEnd { class SymbolIndexerTask; -class SymbolIndexerTaskQueueInterface +class SymbolIndexerTaskQueueInterface : public QueueInterface { 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 std::vector &projectPartIds) = 0 /* [[expects: std::is_sorted(projectPartIds)]] */; - virtual void processTasks() = 0; protected: ~SymbolIndexerTaskQueueInterface() = default; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp deleted file mode 100644 index e9f5cbe285b..00000000000 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/**************************************************************************** -** -** 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 "symbolindexertaskscheduler.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -namespace ClangBackEnd { -namespace { -#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) -template -class CallableEvent : public QEvent { -public: - using Callable = std::decay_t; - CallableEvent(Callable &&callable) - : QEvent(QEvent::None), - callable(std::move(callable)) - {} - CallableEvent(const Callable &callable) - : QEvent(QEvent::None), - callable(callable) - {} - - ~CallableEvent() - { - callable(); - } -public: - Callable callable; -}; - -template -void executeInLoop(Callable &&callable, QObject *object = QCoreApplication::instance()) { - if (QThread *thread = qobject_cast(object)) - object = QAbstractEventDispatcher::instance(thread); - - QCoreApplication::postEvent(object, - new CallableEvent(std::forward(callable)), - Qt::HighEventPriority); -} -#else -template -void executeInLoop(Callable &&callable, QObject *object = QCoreApplication::instance()) { - if (QThread *thread = qobject_cast(object)) - object = QAbstractEventDispatcher::instance(thread); - - QMetaObject::invokeMethod(object, std::forward(callable)); -} -#endif -} - -void SymbolIndexerTaskScheduler::addTasks(std::vector &&tasks) -{ - for (auto &task : tasks) { - auto callWrapper = [&, task=std::move(task)] ( - std::reference_wrapper symbolsCollector) - -> SymbolsCollectorInterface& { - task(symbolsCollector.get(), m_symbolStorage, m_transactionInterface); - executeInLoop([&] { - m_symbolIndexerTaskQueue.processTasks(); - }); - - return symbolsCollector; - }; - m_futures.emplace_back(std::async(m_launchPolicy, - std::move(callWrapper), - std::ref(m_symbolsCollectorManager.unusedSymbolsCollector()))); - } -} - -const std::vector &SymbolIndexerTaskScheduler::futures() const -{ - return m_futures; -} - -uint SymbolIndexerTaskScheduler::freeSlots() -{ - removeFinishedFutures(); - - if (m_isDisabled) - return 0; - - return uint(std::max(int(m_hardware_concurrency) - int(m_futures.size()), 0)); -} - -void SymbolIndexerTaskScheduler::syncTasks() -{ - for (auto &future : m_futures) - future.wait(); -} - -void SymbolIndexerTaskScheduler::disable() -{ - m_isDisabled = true; -} - -void SymbolIndexerTaskScheduler::removeFinishedFutures() -{ - auto notReady = [] (Future &future) { - return future.wait_for(std::chrono::duration::zero()) != std::future_status::ready; - }; - - auto split = std::partition(m_futures.begin(), m_futures.end(), notReady); - - std::for_each(split, m_futures.end(), [] (Future &future) { - SymbolsCollectorInterface &symbolCollector = future.get(); - symbolCollector.setIsUsed(false); - symbolCollector.clear(); - }); - - m_futures.erase(split, m_futures.end()); -} - -} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h b/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h deleted file mode 100644 index 6182376dab0..00000000000 --- a/src/tools/clangrefactoringbackend/source/symbolindexertaskscheduler.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** 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 "symbolindexertaskschedulerinterface.h" -#include "symbolindexertask.h" - -#include -#include -#include - -namespace Sqlite { -class TransactionInterface; -}; - -namespace ClangBackEnd { - -class FilePathCachingInterface; -class SymbolsCollectorInterface; -class SymbolsCollectorManagerInterface; -class SymbolIndexerTaskQueueInterface; -class SymbolStorageInterface; - -class SymbolIndexerTaskScheduler final : public SymbolIndexerTaskSchedulerInterface -{ -public: - using Task = SymbolIndexerTask::Callable; - using Future = std::future; - - SymbolIndexerTaskScheduler(SymbolsCollectorManagerInterface &symbolsCollectorManager, - SymbolStorageInterface &symbolStorage, - Sqlite::TransactionInterface &transactionInterface, - SymbolIndexerTaskQueueInterface &symbolIndexerTaskQueue, - 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) - {} - - void addTasks(std::vector &&tasks); - - const std::vector &futures() const; - - uint freeSlots(); - - void syncTasks(); - - void disable(); - -private: - void removeFinishedFutures(); - -private: - std::vector m_futures; - SymbolsCollectorManagerInterface &m_symbolsCollectorManager; - SymbolStorageInterface &m_symbolStorage; - Sqlite::TransactionInterface &m_transactionInterface; - SymbolIndexerTaskQueueInterface &m_symbolIndexerTaskQueue; - uint m_hardware_concurrency; - std::launch m_launchPolicy; - bool m_isDisabled = false; -}; - -} // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h index 8f7821bddbd..918edb626a9 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexing.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h @@ -30,9 +30,9 @@ #include "storagesqlitestatementfactory.h" #include "symbolindexer.h" #include "symbolscollector.h" -#include "symbolscollectormanager.h" +#include "processormanager.h" #include "symbolindexertaskqueue.h" -#include "symbolindexertaskscheduler.h" +#include "taskscheduler.h" #include "symbolstorage.h" #include @@ -48,19 +48,40 @@ namespace ClangBackEnd { +class SymbolsCollectorManager; + +class SymbolsCollectorManager final : public ClangBackEnd::ProcessorManager +{ +public: + using Processor = SymbolsCollector; + SymbolsCollectorManager(const ClangBackEnd::GeneratedFiles &generatedFiles, + Sqlite::Database &database) + : ProcessorManager(generatedFiles), + m_database(database) + {} + +protected: + std::unique_ptr createProcessor() const + { + return std::make_unique(m_database); + } + +private: + Sqlite::Database &m_database; +}; + class SymbolIndexing final : public SymbolIndexingInterface { public: using StatementFactory = ClangBackEnd::StorageSqliteStatementFactory; using Storage = ClangBackEnd::SymbolStorage; - SymbolIndexing(Sqlite::Database &database, FilePathCachingInterface &filePathCache, const GeneratedFiles &generatedFiles) : m_filePathCache(filePathCache), m_statementFactory(database), - m_collectorManger(database, generatedFiles), - m_indexerScheduler(m_collectorManger, m_symbolStorage, database, m_indexerQueue, std::thread::hardware_concurrency()) + m_collectorManger(generatedFiles, database), + m_indexerScheduler(m_collectorManger, m_indexerQueue, std::thread::hardware_concurrency()) { } @@ -86,12 +107,13 @@ public: void updateProjectParts(V2::ProjectPartContainers &&projectParts) override; private: + using SymbolIndexerTaskScheduler = TaskScheduler; FilePathCachingInterface &m_filePathCache; StatementFactory m_statementFactory; Storage m_symbolStorage{m_statementFactory}; ClangPathWatcher m_sourceWatcher{m_filePathCache}; FileStatusCache m_fileStatusCache{m_filePathCache}; - SymbolsCollectorManager m_collectorManger; + SymbolsCollectorManager m_collectorManger; SymbolIndexerTaskScheduler m_indexerScheduler; SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler}; SymbolIndexer m_indexer{m_indexerQueue, diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp index 53e0bbba6e8..afa01de2e9c 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollector.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolscollector.cpp @@ -129,6 +129,10 @@ void SymbolsCollector::collectSymbols() &m_collectMacrosSourceFileCallbacks).get()); } +void SymbolsCollector::doInMainThreadAfterFinished() +{ +} + const SymbolEntries &SymbolsCollector::symbols() const { return m_symbolEntries; diff --git a/src/tools/clangrefactoringbackend/source/symbolscollector.h b/src/tools/clangrefactoringbackend/source/symbolscollector.h index 70213555d64..beb610d1901 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollector.h +++ b/src/tools/clangrefactoringbackend/source/symbolscollector.h @@ -54,6 +54,8 @@ public: void collectSymbols() override; + void doInMainThreadAfterFinished() override; + const SymbolEntries &symbols() const override; const SourceLocationEntries &sourceLocations() const override; const FilePathIds &sourceFiles() const override; diff --git a/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h b/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h index 540866630f7..0b7e00509df 100644 --- a/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolscollectorinterface.h @@ -31,7 +31,7 @@ #include "sourcelocationentry.h" #include "usedmacro.h" -#include +#include #include @@ -40,20 +40,10 @@ namespace ClangBackEnd { -class SymbolsCollectorInterface +class SymbolsCollectorInterface : public ProcessorInterface { public: - SymbolsCollectorInterface() = default; - virtual ~SymbolsCollectorInterface() = default; - SymbolsCollectorInterface(const SymbolsCollectorInterface &) = delete; - SymbolsCollectorInterface &operator=(const SymbolsCollectorInterface &) = delete; - virtual void setFile(FilePathId filePathId, const Utils::SmallStringVector &arguments) = 0; - - virtual void setUnsavedFiles(const V2::FileContainers &unsavedFiles) = 0; - - virtual void clear() = 0; - virtual void collectSymbols() = 0; virtual const SymbolEntries &symbols() const = 0; @@ -62,9 +52,6 @@ public: virtual const UsedMacros &usedMacros() const = 0; virtual const FileStatuses &fileStatuses() const = 0; virtual const SourceDependencies &sourceDependencies() const = 0; - - virtual bool isUsed() const = 0; - virtual void setIsUsed(bool isUsed) = 0; }; } // namespace ClangBackEnd diff --git a/tests/unit/unittest/data/includecollector_faulty.cpp b/tests/unit/unittest/data/includecollector_faulty.cpp new file mode 100644 index 00000000000..a25ff9062c0 --- /dev/null +++ b/tests/unit/unittest/data/includecollector_faulty.cpp @@ -0,0 +1 @@ +#include "includecollector_faulty.h" diff --git a/tests/unit/unittest/data/includecollector_faulty.h b/tests/unit/unittest/data/includecollector_faulty.h new file mode 100644 index 00000000000..4a0601f95b1 --- /dev/null +++ b/tests/unit/unittest/data/includecollector_faulty.h @@ -0,0 +1,8 @@ +#pragma once + +IDENTIFICATION DIVISION. +PROGRAM-ID. HELLO-WORLD. +* simple hello world program +PROCEDURE DIVISION. + DISPLAY 'Hello world!'. + STOP RUN. diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h index e7fe88065b6..4f88488b4ef 100644 --- a/tests/unit/unittest/google-using-declarations.h +++ b/tests/unit/unittest/google-using-declarations.h @@ -27,6 +27,7 @@ #include + using testing::_; using testing::A; using testing::AllOf; @@ -34,6 +35,8 @@ using testing::An; using testing::AnyNumber; using testing::AnyOf; using testing::Assign; +using testing::ByMove; +using testing::ByRef; using testing::Contains; using testing::ElementsAre; using testing::Field; diff --git a/tests/unit/unittest/googletest.h b/tests/unit/unittest/googletest.h index 6b01852fe21..e5d221d6a88 100644 --- a/tests/unit/unittest/googletest.h +++ b/tests/unit/unittest/googletest.h @@ -25,10 +25,15 @@ #pragma once +#ifdef __GNUC__ +#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" +#endif + #include #include #include #include + #include "compare-operators.h" #include "conditionally-disabled-tests.h" diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index c2ce8a9cbc3..ea59cc59422 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -621,7 +621,8 @@ std::ostream &operator<<(std::ostream &out, const ProjectPartPch &projectPartPch { out << "(" << projectPartPch.projectPartId << ", " - << projectPartPch.pchPath << ")"; + << projectPartPch.pchPath << ", " + << projectPartPch.lastModified << ")"; return out; } diff --git a/tests/unit/unittest/mockpchcreator.h b/tests/unit/unittest/mockpchcreator.h index 91ef19402b2..4d1fd24707d 100644 --- a/tests/unit/unittest/mockpchcreator.h +++ b/tests/unit/unittest/mockpchcreator.h @@ -35,13 +35,21 @@ class MockPchCreator : public ClangBackEnd::PchCreatorInterface { public: - MOCK_METHOD1(generatePchs, - void(const ClangBackEnd::V2::ProjectPartContainers &projectParts)); - MOCK_METHOD0(takeProjectsIncludes, - std::vector()); + MOCK_METHOD1(generatePch, + void(const ClangBackEnd::V2::ProjectPartContainer &projectPart)); + MOCK_METHOD0(takeProjectIncludes, + ClangBackEnd::IdPaths()); + MOCK_METHOD0(projectPartPch, + const ClangBackEnd::ProjectPartPch &()); + MOCK_METHOD1(setUnsavedFiles, + void (const ClangBackEnd::V2::FileContainers &fileContainers)); + MOCK_METHOD0(clear, + void()); + MOCK_METHOD0(doInMainThreadAfterFinished, + void()); + MOCK_CONST_METHOD0(isUsed, + bool()); + MOCK_METHOD1(setIsUsed, + void(bool)); - void generatePchs(std::vector &&projectParts) override - { - generatePchs(projectParts); - } }; diff --git a/tests/unit/unittest/mockprecompiledheaderstorage.h b/tests/unit/unittest/mockprecompiledheaderstorage.h index 60ba3525842..11493a55601 100644 --- a/tests/unit/unittest/mockprecompiledheaderstorage.h +++ b/tests/unit/unittest/mockprecompiledheaderstorage.h @@ -29,7 +29,7 @@ #include -class MockPrecompiledHeaderStorage : public ClangPchManager::PrecompiledHeaderStorageInterface +class MockPrecompiledHeaderStorage : public ClangBackEnd::PrecompiledHeaderStorageInterface { public: MOCK_METHOD3(insertPrecompiledHeader, diff --git a/tests/unit/unittest/mockprocessor.h b/tests/unit/unittest/mockprocessor.h new file mode 100644 index 00000000000..040d537ed42 --- /dev/null +++ b/tests/unit/unittest/mockprocessor.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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 "googletest.h" + +#include + +namespace Sqlite { +class Database; +} + +class MockProcessor : public ClangBackEnd::ProcessorInterface +{ +public: + MockProcessor() + { + ON_CALL(*this, setIsUsed(_)).WillByDefault(Invoke(this, &MockProcessor::setIsUsed2)); + ON_CALL(*this, isUsed()).WillByDefault(Invoke(this, &MockProcessor::isUsed2)); + ON_CALL(*this, setUnsavedFiles(_)).WillByDefault(Invoke(this, &MockProcessor::setHasUnsavedFiles)); + } + + MOCK_METHOD1(setUnsavedFiles, + void(const ClangBackEnd::V2::FileContainers &unsavedFiles)); + + MOCK_METHOD0(clear, + void()); + + MOCK_CONST_METHOD0(isUsed, + bool()); + + MOCK_METHOD1(setIsUsed, + void(bool)); + + MOCK_METHOD0(doInMainThreadAfterFinished, + void()); + + void setIsUsed2(bool isUsed) + { + used = isUsed; + } + + bool isUsed2() const + { + return used; + } + + void setHasUnsavedFiles(const ClangBackEnd::V2::FileContainers &unsavedFiles) + { + hasUnsavedFiles = true; + } + +public: + bool used = false; + bool hasUnsavedFiles = false; +}; diff --git a/tests/unit/unittest/mockpchgeneratornotifier.h b/tests/unit/unittest/mockprocessormanager.h similarity index 77% rename from tests/unit/unittest/mockpchgeneratornotifier.h rename to tests/unit/unittest/mockprocessormanager.h index fe5b8b2af4f..3252aada194 100644 --- a/tests/unit/unittest/mockpchgeneratornotifier.h +++ b/tests/unit/unittest/mockprocessormanager.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -23,16 +23,14 @@ ** ****************************************************************************/ -#pragma once - #include "googletest.h" -#include +#include -class MockPchGeneratorNotifier : public ClangBackEnd::PchGeneratorNotifierInterface +class MockProcessorManager : public ClangBackEnd::ProcessorManagerInterface { public: - MOCK_METHOD2(taskFinished, - void (ClangBackEnd::TaskFinishStatus status, - const ClangBackEnd::ProjectPartPch &projectPartPch)); + using Processor = ClangBackEnd::ProcessorInterface; + + MOCK_METHOD0(unusedProcessor, ClangBackEnd::ProcessorInterface &()); }; diff --git a/tests/unit/unittest/mockprojectpartqueue.h b/tests/unit/unittest/mockprojectpartqueue.h new file mode 100644 index 00000000000..8d1ec1f66c3 --- /dev/null +++ b/tests/unit/unittest/mockprojectpartqueue.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** 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 MockProjectPartQueue : public ClangBackEnd::ProjectPartQueueInterface +{ +public: + MOCK_METHOD1(addProjectParts, + void (const ClangBackEnd::V2::ProjectPartContainers &projectParts)); + MOCK_METHOD1(removeProjectParts, + void (const Utils::SmallStringVector &projectsPartIds)); + + MOCK_METHOD0(processEntries, void ()); + + void addProjectParts(ClangBackEnd::V2::ProjectPartContainers &&projectParts) override + { + addProjectParts(projectParts); + } +}; diff --git a/tests/unit/unittest/mocksymbolscollectormanager.h b/tests/unit/unittest/mockqueue.h similarity index 83% rename from tests/unit/unittest/mocksymbolscollectormanager.h rename to tests/unit/unittest/mockqueue.h index aedd196c60a..74c35139149 100644 --- a/tests/unit/unittest/mocksymbolscollectormanager.h +++ b/tests/unit/unittest/mockqueue.h @@ -27,12 +27,11 @@ #include "googletest.h" -#include +#include -class MockSymbolsCollectorManager : public ClangBackEnd::SymbolsCollectorManagerInterface +class MockQueue : public ClangBackEnd::QueueInterface { public: - MOCK_METHOD0(unusedSymbolsCollector, - ClangBackEnd::SymbolsCollectorInterface & ()); - + MOCK_METHOD0(processEntries, void()); }; + diff --git a/tests/unit/unittest/mocksymbolindexertaskqueue.h b/tests/unit/unittest/mocksymbolindexertaskqueue.h index 52be4cb9426..7fb0d3f0bd7 100644 --- a/tests/unit/unittest/mocksymbolindexertaskqueue.h +++ b/tests/unit/unittest/mocksymbolindexertaskqueue.h @@ -36,5 +36,5 @@ public: void (std::vector &&tasks)); MOCK_METHOD1(removeTasks, void (const std::vector &projectPartIds)); - MOCK_METHOD0(processTasks, void()); + MOCK_METHOD0(processEntries, void()); }; diff --git a/tests/unit/unittest/mocksymbolscollector.h b/tests/unit/unittest/mocksymbolscollector.h index 1bced44da92..b41a4bcd4ac 100644 --- a/tests/unit/unittest/mocksymbolscollector.h +++ b/tests/unit/unittest/mocksymbolscollector.h @@ -60,6 +60,9 @@ public: MOCK_METHOD0(clear, void()); + MOCK_METHOD0(doInMainThreadAfterFinished, + void()); + MOCK_CONST_METHOD0(symbols, const ClangBackEnd::SymbolEntries &()); diff --git a/tests/unit/unittest/mocksymbolindexertaskscheduler.h b/tests/unit/unittest/mocktaskscheduler.h similarity index 77% rename from tests/unit/unittest/mocksymbolindexertaskscheduler.h rename to tests/unit/unittest/mocktaskscheduler.h index c3b70ca93c9..647e8aefc0d 100644 --- a/tests/unit/unittest/mocksymbolindexertaskscheduler.h +++ b/tests/unit/unittest/mocktaskscheduler.h @@ -27,17 +27,19 @@ #include "googletest.h" -#include +#include +#include -class MockSymbolIndexerTaskScheduler : public ClangBackEnd::SymbolIndexerTaskSchedulerInterface +template +class MockTaskScheduler : public ClangBackEnd::TaskSchedulerInterface { public: - MOCK_METHOD1(addTasks, - void (const std::vector &)); + MOCK_METHOD1_T(addTasks, + void (const std::vector &)); MOCK_METHOD0(freeSlots, uint ()); - void addTasks(std::vector &&tasks) override + void addTasks(std::vector &&tasks) { addTasks(tasks); } diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index 44bbcc7e1ce..cd35d7fcae4 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -27,14 +27,15 @@ #include "fakeprocess.h" -#include "mockpchgeneratornotifier.h" +#include "mockclangpathwatcher.h" +#include "mockpchmanagerclient.h" #include "testenvironment.h" #include #include #include #include -#include +#include #include @@ -62,25 +63,28 @@ class PchCreator: public ::testing::Test protected: void SetUp() { - generatedFiles.update({generatedFile}); + creator.setUnsavedFiles({generatedFile}); } ClangBackEnd::FilePathId id(ClangBackEnd::FilePathView path) { - return filePathCache.filePathId(path); + return creator.filePathCache().filePathId(path); } protected: - GeneratedFiles generatedFiles; 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"; FilePath header2Path = TESTDATA_DIR "/includecollector_header2.h"; Utils::SmallStringView generatedFileName = "includecollector_generated_file.h"; FilePath generatedFilePath = TESTDATA_DIR "/includecollector_generated_file.h"; + TestEnvironment environment; + FileContainer generatedFile{{TESTDATA_DIR, generatedFileName}, "#pragma once", {}}; + NiceMock mockPchManagerClient; + NiceMock mockClangPathWatcher; + ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient, mockClangPathWatcher}; ProjectPartContainer projectPart1{"project1", {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, {{"DEFINE", "1"}}, @@ -93,90 +97,10 @@ protected: {"/includes"}, {id(header2Path)}, {id(main2Path)}}; - TestEnvironment environment; - FileContainer generatedFile{{TESTDATA_DIR, generatedFileName}, "#pragma once", {}}; - NiceMock mockPchGeneratorNotifier; - ClangBackEnd::PchGenerator generator{environment, &mockPchGeneratorNotifier}; - ClangBackEnd::PchCreator creator{{projectPart1.clone(),projectPart2.clone()}, - environment, - filePathCache, - &generator, - generatedFiles}; }; using PchCreatorSlowTest = PchCreator; using PchCreatorVerySlowTest = PchCreator; -TEST_F(PchCreator, CreateGlobalHeaderPaths) -{ - auto filePaths = creator.generateGlobalHeaderPaths(); - - ASSERT_THAT(filePaths, - UnorderedElementsAre(header1Path, header2Path, generatedFilePath)); -} - -TEST_F(PchCreator, CreateGlobalSourcePaths) -{ - auto filePaths = creator.generateGlobalSourcePaths(); - - ASSERT_THAT(filePaths, - UnorderedElementsAre(main1Path, main2Path)); -} - -TEST_F(PchCreator, CreateGlobalHeaderAndSourcePaths) -{ - auto filePaths = creator.generateGlobalHeaderAndSourcePaths(); - - ASSERT_THAT(filePaths, - UnorderedElementsAre(main1Path, main2Path, header1Path, header2Path, generatedFilePath)); -} - -TEST_F(PchCreator, CreateGlobalArguments) -{ - auto arguments = creator.generateGlobalArguments(); - - ASSERT_THAT(arguments, ElementsAre("-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header", "-I", TESTDATA_DIR, "-x" , "c++-header", "-Wno-pragma-once-outside-header")); -} - -TEST_F(PchCreator, CreateGlobalCommandLine) -{ - auto arguments = creator.generateGlobalCommandLine(); - - ASSERT_THAT(arguments, ElementsAre(environment.clangCompilerPath(), "-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header", "-I", TESTDATA_DIR, "-x" , "c++-header", "-Wno-pragma-once-outside-header")); -} - -TEST_F(PchCreatorVerySlowTest, CreateGlobalPchIncludes) -{ - auto includeIds = creator.generateGlobalPchIncludeIds(); - - ASSERT_THAT(includeIds, - AllOf(Contains(id(TESTDATA_DIR "/includecollector_external3.h")), - Contains(id(TESTDATA_DIR "/includecollector_external1.h")), - Contains(id(TESTDATA_DIR "/includecollector_external2.h")))); -} - -TEST_F(PchCreatorVerySlowTest, CreateGlobalPchFileContent) -{ - auto content = creator.generateGlobalPchHeaderFileContent(); - - ASSERT_THAT(std::string(content), - AllOf(HasSubstr("#include \"" TESTDATA_DIR "/includecollector_external3.h\"\n"), - HasSubstr("#include \"" TESTDATA_DIR "/includecollector_external1.h\"\n"), - HasSubstr("#include \"" TESTDATA_DIR "/includecollector_external2.h\"\n"))); -} - -TEST_F(PchCreatorVerySlowTest, CreateGlobalPchHeaderFile) -{ - auto file = creator.generateGlobalPchHeaderFile(); - file->open(QIODevice::ReadOnly); - - auto content = file->readAll(); - - ASSERT_THAT(content.toStdString(), - AllOf(HasSubstr("#include \"" TESTDATA_DIR "/includecollector_external3.h\"\n"), - HasSubstr("#include \"" TESTDATA_DIR "/includecollector_external1.h\"\n"), - HasSubstr("#include \"" TESTDATA_DIR "/includecollector_external2.h\"\n"))); -} - TEST_F(PchCreator, ConvertToQStringList) { auto arguments = creator.convertToQStringList({"-I", TESTDATA_DIR}); @@ -184,23 +108,6 @@ TEST_F(PchCreator, ConvertToQStringList) ASSERT_THAT(arguments, ElementsAre(QString("-I"), QString(TESTDATA_DIR))); } -TEST_F(PchCreator, CreateGlobalPchCompilerArguments) -{ - auto arguments = creator.generateGlobalPchCompilerArguments(); - - ASSERT_THAT(arguments, ElementsAre("-x","c++-header", "-Xclang", "-emit-pch", "-o", EndsWith(".pch"), EndsWith(".h"))); -} - -TEST_F(PchCreator, CreateGlobalClangCompilerArguments) -{ - auto arguments = creator.generateGlobalClangCompilerArguments(); - - ASSERT_THAT(arguments, AllOf(Contains("-Wno-pragma-once-outside-header"), - Contains("-emit-pch"), - Contains("-o"), - Not(Contains(environment.clangCompilerPath())))); -} - TEST_F(PchCreator, CreateProjectPartCommandLine) { auto commandLine = creator.generateProjectPartCommandLine(projectPart1); @@ -275,10 +182,6 @@ TEST_F(PchCreator, CreateProjectPartPchCompilerArguments) ASSERT_THAT(arguments, AllOf(Contains("-x"), Contains("c++-header"), -// Contains("-Xclang"), -// Contains("-include-pch"), -// Contains("-Xclang"), -// Contains(EndsWith(".pch")), Contains("-Xclang"), Contains("-emit-pch"), Contains("-o"), @@ -295,63 +198,90 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments) Not(Contains(environment.clangCompilerPath())))); } -TEST_F(PchCreatorVerySlowTest, ProjectPartPchsExistsAfterCreation) -{ - creator.generateGlobalPch(); - - creator.generateProjectPartPch(projectPart1); - - ASSERT_TRUE(QFileInfo::exists(QString(creator.generateProjectPathPchHeaderFilePath(projectPart1)))); -} - -TEST_F(PchCreatorVerySlowTest, DISABLED_CreatePartPchs) -{ - creator.generateGlobalPch(); - - auto includePaths = creator.generateProjectPartPch(projectPart1); - - ASSERT_THAT(includePaths.id, projectPart1.projectPartId); - ASSERT_THAT(includePaths.filePathIds, - AllOf(Contains(FilePathId{1, 1}), - Contains(FilePathId{1, 2}), - Contains(FilePathId{1, 3}))); -} - TEST_F(PchCreatorVerySlowTest, IncludesForCreatePchsForProjectParts) { - creator.generatePchs(); + creator.generatePch(projectPart1); - ASSERT_THAT(creator.takeProjectsIncludes(), - ElementsAre(Field(&IdPaths::id, "project1"), - Field(&IdPaths::id, "project2"))); + ASSERT_THAT(creator.takeProjectIncludes().id, "project1"); } -TEST_F(PchCreatorVerySlowTest, ProjectPartPchsForCreatePchsForProjectParts) +TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient) { - EXPECT_CALL(mockPchGeneratorNotifier, - taskFinished(ClangBackEnd::TaskFinishStatus::Successfully, - Field(&ProjectPartPch::projectPartId, "project1"))); - EXPECT_CALL(mockPchGeneratorNotifier, - taskFinished(ClangBackEnd::TaskFinishStatus::Successfully, - Field(&ProjectPartPch::projectPartId, "project2"))); + creator.generatePch(projectPart1); - creator.generatePchs(); + EXPECT_CALL(mockPchManagerClient, + precompiledHeadersUpdated( + Field(&ClangBackEnd::PrecompiledHeadersUpdatedMessage::projectPartPchs, + ElementsAre(Eq(creator.projectPartPch()))))); + + creator.doInMainThreadAfterFinished(); +} + +TEST_F(PchCreatorVerySlowTest, UpdateFileWatcherIncludes) +{ + creator.generatePch(projectPart1); + + EXPECT_CALL(mockClangPathWatcher, + updateIdPaths(ElementsAre(creator.projectIncludes()))); + + creator.doInMainThreadAfterFinished(); } TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts) { - creator.generatePchs(); + creator.generatePch(projectPart1); - ASSERT_THAT(creator.takeProjectsIncludes(), - ElementsAre(AllOf(Field(&IdPaths::id, "project1"), - Field(&IdPaths::filePathIds, AllOf(Contains(id(TESTDATA_DIR "/includecollector_header2.h")), - Contains(id(TESTDATA_DIR "/includecollector_external1.h")), - Contains(id(TESTDATA_DIR "/includecollector_external2.h"))))), - AllOf(Field(&IdPaths::id, "project2"), - Field(&IdPaths::filePathIds, AllOf(Contains(id(TESTDATA_DIR "/includecollector_external1.h")), - Contains(id(TESTDATA_DIR "/includecollector_external3.h")), - Contains(id(TESTDATA_DIR "/includecollector_header1.h")), - Contains(id(TESTDATA_DIR "/includecollector_external2.h"))))))); + ASSERT_THAT(creator.takeProjectIncludes(), + AllOf(Field(&IdPaths::id, "project1"), + Field(&IdPaths::filePathIds, AllOf(Contains(id(TESTDATA_DIR "/includecollector_header2.h")), + Contains(id(TESTDATA_DIR "/includecollector_external1.h")), + Contains(id(TESTDATA_DIR "/includecollector_external2.h")))))); +} + +TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart) +{ + creator.generatePch(projectPart1); + + ASSERT_THAT(creator.projectPartPch(), + AllOf(Field(&ProjectPartPch::projectPartId, Eq("project1")), + Field(&ProjectPartPch::pchPath, Not(IsEmpty())), + Field(&ProjectPartPch::lastModified, Not(Eq(-1))))); +} + +TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared) +{ + creator.generatePch(projectPart1); + + creator.clear(); + + ASSERT_THAT(creator.projectPartPch(), ClangBackEnd::ProjectPartPch{}); +} + + +TEST_F(PchCreatorVerySlowTest, ProjectIncludesCleared) +{ + creator.generatePch(projectPart1); + + creator.clear(); + + ASSERT_THAT(creator.projectIncludes(), ClangBackEnd::IdPaths{}); +} + +TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesNoPchForProjectPart) +{ + ProjectPartContainer faultyProjectPart{"faultyProject", + {"-I", TESTDATA_DIR}, + {{"DEFINE", "1"}}, + {"/includes"}, + {}, + {id(TESTDATA_DIR "/includecollector_faulty.cpp")}}; + + creator.generatePch(faultyProjectPart); + + ASSERT_THAT(creator.projectPartPch(), + AllOf(Field(&ProjectPartPch::projectPartId, Eq("faultyProject")), + Field(&ProjectPartPch::pchPath, IsEmpty()), + Field(&ProjectPartPch::lastModified, Eq(-1)))); } TEST_F(PchCreator, CreateProjectPartSourcesContent) @@ -361,5 +291,12 @@ TEST_F(PchCreator, CreateProjectPartSourcesContent) ASSERT_THAT(content, Eq("#include \"" TESTDATA_DIR "/includecollector_main3.cpp\"\n")); } +TEST_F(PchCreator, Call) +{ + auto content = creator.generateProjectPartSourcesContent(projectPart1); + + ASSERT_THAT(content, Eq("#include \"" TESTDATA_DIR "/includecollector_main3.cpp\"\n")); +} + } diff --git a/tests/unit/unittest/pchgenerator-test.cpp b/tests/unit/unittest/pchgenerator-test.cpp deleted file mode 100644 index 2bce237833c..00000000000 --- a/tests/unit/unittest/pchgenerator-test.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 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 "fakeprocess.h" -#include "testenvironment.h" -#include "mockpchgeneratornotifier.h" - -#include - -namespace { - -using testing::_; -using testing::Contains; -using testing::Eq; -using testing::NiceMock; -using testing::Not; -using testing::PrintToString; -using ClangBackEnd::TaskFinishStatus; - -MATCHER_P(ContainsProcess, process, - std::string(negation ? "isn't" : "is") - + " process " + PrintToString(process)) -{ - auto found = std::find_if(arg.begin(), - arg.end(), - [&] (const std::unique_ptr &processOwner) { - return processOwner.get() == process; - }); - - return found != arg.end(); -} - -class PchGenerator : public testing::Test -{ -protected: - TestEnvironment environment; - NiceMock mockNotifier; - ClangBackEnd::PchGenerator generator{environment, &mockNotifier}; - Utils::SmallStringVector compilerArguments = {"-DXXXX", "-Ifoo"}; - ClangBackEnd::ProjectPartPch projectPartPch{"projectPartId", "/path/to/pch", 1}; -}; - -TEST_F(PchGenerator, ProcessFinished) -{ - EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Successfully, std::move(projectPartPch))); - - generator.startTask(compilerArguments.clone(), projectPartPch.clone()); -} - -TEST_F(PchGenerator, ProcessFinishedForDeferredProcess) -{ - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - generator.startTask(compilerArguments.clone(), projectPartPch.clone()); - - EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Successfully, std::move(projectPartPch))) - .Times(3); - - generator.startTask(compilerArguments.clone(), projectPartPch.clone()); - process->finish(); -} - -TEST_F(PchGenerator, ProcessSuccessfullyFinished) -{ - EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Unsuccessfully, std::move(projectPartPch))); - - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - process->finishUnsuccessfully(); -} - -TEST_F(PchGenerator, ProcessSuccessfullyFinishedByWrongExitCode) -{ - EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Unsuccessfully, std::move(projectPartPch))); - - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - process->finishUnsuccessfully(); -} - -TEST_F(PchGenerator, AddTaskAddsProcessToProcesses) -{ - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - ASSERT_THAT(generator.runningProcesses(), ContainsProcess(process)); -} - -TEST_F(PchGenerator, RemoveProcessAfterFinishingProcess) -{ - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - process->finish(); - - ASSERT_THAT(generator.runningProcesses(), Not(ContainsProcess(process))); -} - -TEST_F(PchGenerator, ProcessSuccessfullyFinishedByCrash) -{ - EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Unsuccessfully, std::move(projectPartPch))); - - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - process->finishByCrash(); -} - -TEST_F(PchGenerator, CreateProcess) -{ - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - ASSERT_THAT(generator.runningProcesses(), ContainsProcess(process)); -} - -TEST_F(PchGenerator, DeleteProcess) -{ - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - generator.deleteProcess(process); - - ASSERT_THAT(generator.runningProcesses(), Not(ContainsProcess(process))); -} - -TEST_F(PchGenerator, StartProcessApplicationPath) -{ - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - ASSERT_THAT(process->applicationPath(), environment.clangCompilerPath()); - -} - -TEST_F(PchGenerator, SetCompilerArguments) -{ - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - ASSERT_THAT(process->arguments(), compilerArguments); -} - -TEST_F(PchGenerator, ProcessIsStartedAfterAddingTask) -{ - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - ASSERT_TRUE(process->isStarted()); -} - -TEST_F(PchGenerator, DeferProcess) -{ - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - auto deferProcess = generator.deferProcess(); - - ASSERT_TRUE(deferProcess); -} - -TEST_F(PchGenerator, ThirdTaskIsDeferred) -{ - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - ASSERT_THAT(process, generator.deferredProcesses().back().get()); -} - -TEST_F(PchGenerator, ThirdTaskIsNotRunning) -{ - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - ASSERT_THAT(generator.runningProcesses(), Not(ContainsProcess(process))); -} - -TEST_F(PchGenerator, DoNotDeferProcess) -{ - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - auto deferProcess = generator.deferProcess(); - - ASSERT_FALSE(deferProcess); -} - -TEST_F(PchGenerator, DoNotActivateIfNothingIsDeferred) -{ - generator.activateNextDeferredProcess(); -} - -TEST_F(PchGenerator, AfterActivationProcessIsRunning) -{ - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); - - generator.activateNextDeferredProcess(); - - ASSERT_THAT(generator.runningProcesses(), ContainsProcess(process)); -} - -} diff --git a/tests/unit/unittest/pchmanagerclient-test.cpp b/tests/unit/unittest/pchmanagerclient-test.cpp index 8c13055c5e6..eceb32b0b0b 100644 --- a/tests/unit/unittest/pchmanagerclient-test.cpp +++ b/tests/unit/unittest/pchmanagerclient-test.cpp @@ -52,8 +52,7 @@ class PchManagerClient : public ::testing::Test { protected: NiceMock mockPchManagerServer; - NiceMock mockPrecompiledHeaderStorage; - ClangPchManager::PchManagerClient client{mockPrecompiledHeaderStorage}; + ClangPchManager::PchManagerClient client; NiceMock mockPchManagerNotifier{client}; Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; @@ -156,20 +155,4 @@ TEST_F(PchManagerClient, ProjectPartPchForProjectPartIdIsUpdated) 42); } -TEST_F(PchManagerClient, ProjectPartPchAddedToDatabase) -{ - EXPECT_CALL(mockPrecompiledHeaderStorage, insertPrecompiledHeader(TypedEq(projectPartId), - TypedEq(pchFilePath), - TypedEq(1))); - - client.precompiledHeadersUpdated(message.clone()); -} - -TEST_F(PchManagerClient, ProjectPartPchRemovedFromDatabase) -{ - EXPECT_CALL(mockPrecompiledHeaderStorage, deletePrecompiledHeader(TypedEq(projectPartId))); - - projectUpdater.removeProjectParts({QString(projectPartId)}); -} - } diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp index 2e47694262b..731960c4ed9 100644 --- a/tests/unit/unittest/pchmanagerserver-test.cpp +++ b/tests/unit/unittest/pchmanagerserver-test.cpp @@ -27,7 +27,7 @@ #include "mockclangpathwatcher.h" #include "mockpchmanagerclient.h" -#include "mockpchcreator.h" +#include "mockprojectpartqueue.h" #include "mockprojectparts.h" #include "mockgeneratedfiles.h" @@ -46,25 +46,31 @@ using Utils::SmallString; using ClangBackEnd::V2::FileContainer; using ClangBackEnd::V2::FileContainers; using ClangBackEnd::V2::ProjectPartContainer; -using ClangBackEnd::TaskFinishStatus; class PchManagerServer : public ::testing::Test { - void SetUp() override; + void SetUp() override + { + server.setClient(&mockPchManagerClient); + + ON_CALL(mockProjectParts, update(projectParts)) + .WillByDefault(Return(projectParts)); + } + ClangBackEnd::FilePathId id(Utils::SmallStringView path) const { return filePathCache.filePathId(ClangBackEnd::FilePathView(path)); } protected: - NiceMock mockPchCreator; + NiceMock mockProjectPartQueue; NiceMock mockClangPathWatcher; NiceMock mockProjectParts; NiceMock mockGeneratedFiles; Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; - ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockPchCreator, mockProjectParts, mockGeneratedFiles}; + ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockProjectPartQueue, mockProjectParts, mockGeneratedFiles}; NiceMock mockPchManagerClient; SmallString projectPartId1 = "project1"; SmallString projectPartId2 = "project2"; @@ -72,7 +78,7 @@ protected: PathString main2Path = TESTDATA_DIR "/includecollector_main2.cpp"; PathString header1Path = TESTDATA_DIR "/includecollector_header1.h"; PathString header2Path = TESTDATA_DIR "/includecollector_header2.h"; - std::vector idPaths = {{projectPartId1, {{1, 1}, {1, 2}}}}; + ClangBackEnd::IdPaths idPath{projectPartId1, {{1, 1}, {1, 2}}}; ProjectPartContainer projectPart1{projectPartId1.clone(), {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, {{"DEFINE", "1"}}, @@ -86,35 +92,19 @@ protected: {id(header2Path)}, {id(main2Path)}}; std::vector projectParts{projectPart1, projectPart2}; + std::vector projectParts2{projectPart2}; FileContainer generatedFile{{"/path/to/", "file"}, "content", {}}; ClangBackEnd::UpdateProjectPartsMessage updateProjectPartsMessage{Utils::clone(projectParts)}; - ClangBackEnd::ProjectPartPch projectPartPch1{projectPart1.projectPartId.clone(), "/path1/to/pch", 1}; - ClangBackEnd::ProjectPartPch projectPartPch2{projectPart2.projectPartId.clone(), "/path2/to/pch", 1}; - std::vector projectPartPchs{projectPartPch1, projectPartPch2}; - ClangBackEnd::PrecompiledHeadersUpdatedMessage precompiledHeaderUpdatedMessage1{{projectPartPch1}}; - ClangBackEnd::PrecompiledHeadersUpdatedMessage precompiledHeaderUpdatedMessage2{{projectPartPch2}}; ClangBackEnd::RemoveProjectPartsMessage removeProjectPartsMessage{{projectPart1.projectPartId.clone(), projectPart2.projectPartId.clone()}}; }; -TEST_F(PchManagerServer, CallPrecompiledHeadersForSuccessfullyFinishedTask) +TEST_F(PchManagerServer, FilterProjectPartsAndSendThemToQueue) { - EXPECT_CALL(mockPchManagerClient, precompiledHeadersUpdated(precompiledHeaderUpdatedMessage1)); + InSequence s; - server.taskFinished(TaskFinishStatus::Successfully, projectPartPch1); -} - -TEST_F(PchManagerServer, DoNotCallPrecompiledHeadersForUnsuccessfullyFinishedTask) -{ - EXPECT_CALL(mockPchManagerClient, precompiledHeadersUpdated(precompiledHeaderUpdatedMessage1)) - .Times(0); - - server.taskFinished(TaskFinishStatus::Unsuccessfully, projectPartPch1); -} - -TEST_F(PchManagerServer, CallBuildInPchCreator) -{; - EXPECT_CALL(mockPchCreator, generatePchs(updateProjectPartsMessage.projectsParts)); + EXPECT_CALL(mockProjectParts, update(updateProjectPartsMessage.projectsParts)).WillOnce(Return(projectParts2)); + EXPECT_CALL(mockProjectPartQueue, addProjectParts(Eq(projectParts2))); server.updateProjectParts(updateProjectPartsMessage.clone()); } @@ -137,20 +127,6 @@ TEST_F(PchManagerServer, RemoveGeneratedFilesCallsRemove) server.removeGeneratedFiles(removeGeneratedFilesMessage.clone()); } -TEST_F(PchManagerServer, UpdateIncludesOfFileWatcher) -{ - EXPECT_CALL(mockClangPathWatcher, updateIdPaths(idPaths)); - - server.updateProjectParts(updateProjectPartsMessage.clone()); -} - -TEST_F(PchManagerServer, GetChangedProjectPartsFromProjectParts) -{ - EXPECT_CALL(mockProjectParts, update(_)); - - server.updateProjectParts(updateProjectPartsMessage.clone()); -} - TEST_F(PchManagerServer, RemoveIncludesFromFileWatcher) { EXPECT_CALL(mockClangPathWatcher, removeIds(removeProjectPartsMessage.projectsPartIds)); @@ -169,45 +145,16 @@ TEST_F(PchManagerServer, SetPathWatcherNotifier) { EXPECT_CALL(mockClangPathWatcher, setNotifier(_)); - ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockPchCreator, mockProjectParts, mockGeneratedFiles}; + ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockProjectPartQueue, mockProjectParts, mockGeneratedFiles}; } -TEST_F(PchManagerServer, CallProjectsInProjectPartsForIncludeChange) +TEST_F(PchManagerServer, UpdateProjectPartQueueByPathIds) { - server.updateProjectParts(updateProjectPartsMessage.clone()); - - EXPECT_CALL(mockProjectParts, projects(ElementsAre(projectPart1.projectPartId))); + EXPECT_CALL(mockProjectParts, projects(ElementsAre(projectPart1.projectPartId))) + .WillOnce(Return(std::vector{{projectPart1}})); + EXPECT_CALL(mockProjectPartQueue, addProjectParts(ElementsAre(projectPart1))); server.pathsWithIdsChanged({projectPartId1}); } -TEST_F(PchManagerServer, CallGeneratePchsInPchCreatorForIncludeChange) -{ - server.updateProjectParts(updateProjectPartsMessage.clone()); - - EXPECT_CALL(mockPchCreator, generatePchs(ElementsAre(projectPart1))); - - server.pathsWithIdsChanged({projectPartId1}); -} - -TEST_F(PchManagerServer, CallUpdateIdPathsInFileSystemWatcherForIncludeChange) -{ - server.updateProjectParts(updateProjectPartsMessage.clone()); - - EXPECT_CALL(mockClangPathWatcher, updateIdPaths(idPaths)); - - server.pathsWithIdsChanged({projectPartId1}); -} - -void PchManagerServer::SetUp() -{ - server.setClient(&mockPchManagerClient); - - ON_CALL(mockProjectParts, update(projectParts)) - .WillByDefault(Return(projectParts)); - ON_CALL(mockProjectParts, projects(Utils::SmallStringVector{{projectPartId1}})) - .WillByDefault(Return(std::vector{{projectPart1}})); - ON_CALL(mockPchCreator, takeProjectsIncludes()) - .WillByDefault(Return(idPaths)); -} } diff --git a/tests/unit/unittest/precompiledheaderstorage-test.cpp b/tests/unit/unittest/precompiledheaderstorage-test.cpp index 86f46156cf1..3910b9a3706 100644 --- a/tests/unit/unittest/precompiledheaderstorage-test.cpp +++ b/tests/unit/unittest/precompiledheaderstorage-test.cpp @@ -34,7 +34,7 @@ namespace { -using Storage = ClangPchManager::PrecompiledHeaderStorage>; +using Storage = ClangBackEnd::PrecompiledHeaderStorage>; class PrecompiledHeaderStorage : public testing::Test { @@ -133,7 +133,7 @@ TEST_F(PrecompiledHeaderStorage, CompilePrecompiledHeaderStatements) Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; - ASSERT_NO_THROW(ClangPchManager::PrecompiledHeaderStorage<>{database}); + ASSERT_NO_THROW(ClangBackEnd::PrecompiledHeaderStorage<>{database}); } } diff --git a/tests/unit/unittest/processormanager-test.cpp b/tests/unit/unittest/processormanager-test.cpp new file mode 100644 index 00000000000..c5da739b6ce --- /dev/null +++ b/tests/unit/unittest/processormanager-test.cpp @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** 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 "mockprocessor.h" + +#include +#include +#include + +namespace { +using ClangBackEnd::ProcessorInterface; + +class Manager final : public ClangBackEnd::ProcessorManager> +{ +public: + using Processor = NiceMock; + Manager(const ClangBackEnd::GeneratedFiles &generatedFiles) + : ClangBackEnd::ProcessorManager>(generatedFiles) + {} + +protected: + std::unique_ptr> createProcessor() const override + { + return std::make_unique>(); + } +}; + +class ProcessorManager : public testing::Test +{ +protected: + ClangBackEnd::GeneratedFiles generatedFiles; + Manager manager{generatedFiles}; +}; + +TEST_F(ProcessorManager, CreateUnsedProcessor) +{ + manager.unusedProcessor(); + + manager.unusedProcessor(); + + ASSERT_THAT(manager.processors(), SizeIs(2)); +} + +TEST_F(ProcessorManager, ReuseUnsedProcessor) +{ + auto &processor = manager.unusedProcessor(); + processor.setIsUsed(false); + + manager.unusedProcessor(); + + ASSERT_THAT(manager.processors(), SizeIs(1)); +} + +TEST_F(ProcessorManager, AsGetNewUnusedProcessorItIsSetUsed) +{ + auto &processor = manager.unusedProcessor(); + + ASSERT_TRUE(processor.isUsed()); +} + +TEST_F(ProcessorManager, AsGetReusedUnusedProcessorItIsSetUsed) +{ + auto &processor = manager.unusedProcessor(); + processor.setIsUsed(false); + + auto &processor2 = manager.unusedProcessor(); + + ASSERT_TRUE(processor2.isUsed()); +} + +TEST_F(ProcessorManager, UnusedProcessorIsInitializedWithUnsavedFiles) +{ + auto &processor = manager.unusedProcessor(); + + ASSERT_TRUE(processor.hasUnsavedFiles); +} + +TEST_F(ProcessorManager, ReusedProcessorIsInitializedWithUnsavedFiles) +{ + auto &processor = manager.unusedProcessor(); + processor.setIsUsed(false); + + auto &processor2 = manager.unusedProcessor(); + + ASSERT_TRUE(processor2.hasUnsavedFiles); +} + +} diff --git a/tests/unit/unittest/projectpartqueue-test.cpp b/tests/unit/unittest/projectpartqueue-test.cpp new file mode 100644 index 00000000000..3ab0430e39c --- /dev/null +++ b/tests/unit/unittest/projectpartqueue-test.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** 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 "mocktaskscheduler.h" +#include "mockpchcreator.h" +#include "mockprecompiledheaderstorage.h" +#include "mocksqlitetransactionbackend.h" + +#include + +namespace { + +class ProjectPartQueue : public testing::Test +{ +protected: + MockTaskScheduler mockTaskScheduler; + MockPrecompiledHeaderStorage mockPrecompiledHeaderStorage; + MockSqliteTransactionBackend mockSqliteTransactionBackend; + ClangBackEnd::ProjectPartQueue queue{mockTaskScheduler, mockPrecompiledHeaderStorage, mockSqliteTransactionBackend}; + ClangBackEnd::V2::ProjectPartContainer projectPart1{"ProjectPart1", + {"--yi"}, + {{"YI","1"}}, + {"/yi"}, + {{1, 1}}, + {{1, 2}}}; + ClangBackEnd::V2::ProjectPartContainer projectPart2{"ProjectPart2", + {"--er"}, + {{"ER","2"}}, + {"/bar"}, + {{2, 1}}, + {{2, 2}}}; + ClangBackEnd::V2::ProjectPartContainer projectPart2b{"ProjectPart2", + {"--liang"}, + {{"LIANG","3"}}, + {"/liang"}, + {{2, 3}}, + {{2, 2}, {2, 4}}}; + ClangBackEnd::V2::ProjectPartContainer projectPart3{"ProjectPart3", + {"--san"}, + {{"SAN","2"}}, + {"/SAN"}, + {{3, 1}}, + {{3, 2}}}; +}; + +TEST_F(ProjectPartQueue, AddProjectPart) +{ + queue.addProjectParts({projectPart1}); + + queue.addProjectParts({projectPart2}); + + ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPart2)); +} + +TEST_F(ProjectPartQueue, IgnoreIdenticalProjectPart) +{ + queue.addProjectParts({projectPart1, projectPart2}); + + queue.addProjectParts({projectPart1, projectPart2}); + + ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPart2)); +} + +TEST_F(ProjectPartQueue, ReplaceProjectPartWithSameId) +{ + queue.addProjectParts({projectPart1, projectPart2}); + + queue.addProjectParts({projectPart1, projectPart2b, projectPart3}); + + ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPart2b, projectPart3)); +} + +TEST_F(ProjectPartQueue, RemoveProjectPart) +{ + queue.addProjectParts({projectPart1, projectPart2, projectPart3}); + + queue.removeProjectParts({projectPart2.projectPartId}); + + ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPart3)); +} + +TEST_F(ProjectPartQueue, ProcessTasksCallsFreeSlotsAndAddTasksInScheduler) +{ + InSequence s; + queue.addProjectParts({projectPart1, projectPart2}); + + EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); + EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(2))); + + queue.processEntries(); +} + +TEST_F(ProjectPartQueue, CreateTasksSizeEqualsInputSize) +{ + auto tasks = queue.createPchTasks({projectPart1, projectPart2}); + + ASSERT_THAT(tasks, SizeIs(2)); +} + +TEST_F(ProjectPartQueue, CreateTaskFromProjectPart) +{ + InSequence s; + MockPchCreator mockPchCreator; + ClangBackEnd::ProjectPartPch projectPartPch{"project1", "/path/to/pch", 99}; + auto tasks = queue.createPchTasks({projectPart1}); + + EXPECT_CALL(mockPchCreator, generatePch(Eq(projectPart1))); + EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch)); + EXPECT_CALL(mockSqliteTransactionBackend, lock()); + EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); + EXPECT_CALL(mockPrecompiledHeaderStorage, insertPrecompiledHeader(Eq("project1"), Eq("/path/to/pch"), 99)); + EXPECT_CALL(mockSqliteTransactionBackend, commit()); + EXPECT_CALL(mockSqliteTransactionBackend, unlock()); + + tasks.front()(mockPchCreator); +} + +TEST_F(ProjectPartQueue, DeletePchEntryInDatabaseIfNoPchIsGenerated) +{ + InSequence s; + MockPchCreator mockPchCreator; + ClangBackEnd::ProjectPartPch projectPartPch{"project1", "", 0}; + auto tasks = queue.createPchTasks({projectPart1}); + + EXPECT_CALL(mockPchCreator, generatePch(Eq(projectPart1))); + EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch)); + EXPECT_CALL(mockSqliteTransactionBackend, lock()); + EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); + EXPECT_CALL(mockPrecompiledHeaderStorage, deletePrecompiledHeader(Eq("project1"))); + EXPECT_CALL(mockSqliteTransactionBackend, commit()); + EXPECT_CALL(mockSqliteTransactionBackend, unlock()); + + tasks.front()(mockPchCreator); +} + + +//TEST_F(PchManagerClient, ProjectPartPchRemovedFromDatabase) +//{ +// EXPECT_CALL(mockPrecompiledHeaderStorage, deletePrecompiledHeader(TypedEq(projectPartId))); + +// projectUpdater.removeProjectParts({QString(projectPartId)}); +//} + + +} diff --git a/tests/unit/unittest/projectparts-test.cpp b/tests/unit/unittest/projectparts-test.cpp index 50b838ca501..74d1c863381 100644 --- a/tests/unit/unittest/projectparts-test.cpp +++ b/tests/unit/unittest/projectparts-test.cpp @@ -88,16 +88,11 @@ TEST_F(ProjectParts, ProjectPartAdded) ASSERT_THAT(projectParts.projectParts(), ElementsAre(projectPartContainer1)); } -TEST_F(ProjectParts, FilterDublicateProjectPartsForUpdating) -{ - auto updatedProjectParts = projectParts.update({projectPartContainer1, projectPartContainer1}); - - ASSERT_THAT(updatedProjectParts, ElementsAre(projectPartContainer1)); -} - TEST_F(ProjectParts, FilteredProjectPartAdded) { - projectParts.update({projectPartContainer1, projectPartContainer1}); + projectParts.update({projectPartContainer1}); + + projectParts.update({projectPartContainer1}); ASSERT_THAT(projectParts.projectParts(), ElementsAre(projectPartContainer1)); } @@ -120,13 +115,6 @@ TEST_F(ProjectParts, NoDuplicateProjectPartAfterUpdatingWithNotNewProjectPart) ASSERT_THAT(projectParts.projectParts(), ElementsAre(projectPartContainer1)); } -TEST_F(ProjectParts, FilterUniqueProjectParts) -{ - auto updatedProjectParts = projectParts.uniqueProjectParts({projectPartContainer1, projectPartContainer2, projectPartContainer1}); - - ASSERT_THAT(updatedProjectParts, ElementsAre(projectPartContainer1, projectPartContainer2)); -} - TEST_F(ProjectParts, MergeProjectParts) { projectParts.mergeProjectParts({projectPartContainer1, projectPartContainer2}); diff --git a/tests/unit/unittest/projectupdater-test.cpp b/tests/unit/unittest/projectupdater-test.cpp index 35813dfc02b..a3c4b7b7790 100644 --- a/tests/unit/unittest/projectupdater-test.cpp +++ b/tests/unit/unittest/projectupdater-test.cpp @@ -82,7 +82,7 @@ protected: projectPart.files.push_back(header2ProjectFile); projectPart.files.push_back(source1ProjectFile); projectPart.files.push_back(source2ProjectFile); - projectPart.displayName = "project1"; + projectPart.displayName = "projectb"; projectPart.projectMacros = {{"FOO", "2"}, {"BAR", "1"}}; projectPartId = projectPart.id(); @@ -90,7 +90,7 @@ protected: projectPart2.files.push_back(header1ProjectFile); projectPart2.files.push_back(source2ProjectFile); projectPart2.files.push_back(source1ProjectFile); - projectPart2.displayName = "project2"; + projectPart2.displayName = "projectaa"; projectPart2.projectMacros = {{"BAR", "1"}, {"FOO", "2"}}; projectPartId2 = projectPart2.id(); @@ -118,8 +118,7 @@ protected: Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; - MockPrecompiledHeaderStorage mockPrecompiledHeaderStorage; - ClangPchManager::PchManagerClient pchManagerClient{mockPrecompiledHeaderStorage}; + ClangPchManager::PchManagerClient pchManagerClient; MockPchManagerNotifier mockPchManagerNotifier{pchManagerClient}; NiceMock mockPchManagerServer; ClangPchManager::ProjectUpdater updater{mockPchManagerServer, filePathCache}; @@ -202,14 +201,13 @@ TEST_F(ProjectUpdater, CallRemoveProjectParts) EXPECT_CALL(mockPchManagerServer, removeProjectParts(message)); - updater.removeProjectParts({QString(projectPartId), QString(projectPartId2)}); + updater.removeProjectParts({QString(projectPartId2), QString(projectPartId)}); } TEST_F(ProjectUpdater, CallPrecompiledHeaderRemovedInPchManagerProjectUpdater) { ClangPchManager::PchManagerProjectUpdater pchUpdater{mockPchManagerServer, pchManagerClient, filePathCache}; ClangBackEnd::RemoveProjectPartsMessage message{{projectPartId, projectPartId2}}; - EXPECT_CALL(mockPrecompiledHeaderStorage, deletePrecompiledHeader(_)).Times(AnyNumber()); EXPECT_CALL(mockPchManagerNotifier, precompiledHeaderRemoved(projectPartId.toQString())); EXPECT_CALL(mockPchManagerNotifier, precompiledHeaderRemoved(projectPartId2.toQString())); diff --git a/tests/unit/unittest/refactoringprojectupdater-test.cpp b/tests/unit/unittest/refactoringprojectupdater-test.cpp index 799ba44c494..95f00c0f389 100644 --- a/tests/unit/unittest/refactoringprojectupdater-test.cpp +++ b/tests/unit/unittest/refactoringprojectupdater-test.cpp @@ -27,7 +27,6 @@ #include "mockcppmodelmanager.h" #include "mockrefactoringserver.h" -#include "mockprecompiledheaderstorage.h" #include @@ -87,8 +86,7 @@ protected: ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; NiceMock mockRefactoringServer; - NiceMock mockPrecompiledHeaderStorage; - ClangPchManager::PchManagerClient pchManagerClient{mockPrecompiledHeaderStorage}; + ClangPchManager::PchManagerClient pchManagerClient; MockCppModelManager mockCppModelManager; ClangRefactoring::RefactoringProjectUpdater updater{mockRefactoringServer, pchManagerClient, mockCppModelManager, filePathCache}; Utils::SmallString projectPartId; diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index f7364168d0b..c7407297c65 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -34,10 +34,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include #include @@ -60,8 +60,8 @@ using ClangBackEnd::SymbolEntries; using ClangBackEnd::SymbolEntry; using ClangBackEnd::SymbolIndexerTask; using ClangBackEnd::SymbolIndexerTaskQueue; -using ClangBackEnd::SymbolIndexerTaskScheduler; -using ClangBackEnd::SymbolsCollectorManager; +using ClangBackEnd::TaskScheduler; +using ClangBackEnd::ProcessorManager; using ClangBackEnd::SourceDependencies; using ClangBackEnd::SourceLocationEntries; using ClangBackEnd::SourceLocationEntry; @@ -84,6 +84,21 @@ struct Data ClangBackEnd::FilePathCaching filePathCache{database}; }; +class Manager final : public ProcessorManager> +{ +public: + using Processor = NiceMock; + Manager(const ClangBackEnd::GeneratedFiles &generatedFiles) + : ProcessorManager(generatedFiles) + {} + +protected: + std::unique_ptr> createProcessor() const + { + return std::make_unique>(); + } +}; + class SymbolIndexer : public testing::Test { protected: @@ -140,6 +155,7 @@ protected: protected: static std::unique_ptr data; // it can be non const because data holds no tested classes + using Scheduler = TaskScheduler; ClangBackEnd::FilePathCaching &filePathCache = data->filePathCache; ClangBackEnd::FilePathId main1PathId{filePathId(TESTDATA_DIR "/symbolindexer_main1.cpp")}; ClangBackEnd::FilePathId main2PathId{filePathId(TESTDATA_DIR "/symbolindexer_main2.cpp")}; @@ -183,8 +199,8 @@ protected: NiceMock mockPathWatcher; ClangBackEnd::FileStatusCache fileStatusCache{filePathCache}; ClangBackEnd::GeneratedFiles generatedFiles; - SymbolsCollectorManager> collectorManger{data->database, generatedFiles}; - SymbolIndexerTaskScheduler indexerScheduler{collectorManger, mockStorage, mockSqliteTransactionBackend, indexerQueue, 1}; + Manager collectorManger{generatedFiles}; + Scheduler indexerScheduler{collectorManger, indexerQueue, 1}; SymbolIndexerTaskQueue indexerQueue{indexerScheduler}; ClangBackEnd::SymbolIndexer indexer{indexerQueue, mockStorage, @@ -192,7 +208,7 @@ protected: filePathCache, fileStatusCache, mockSqliteTransactionBackend}; - NiceMock &mockCollector{collectorManger.unusedSymbolsCollector()}; + MockSymbolsCollector &mockCollector{static_cast(collectorManger.unusedProcessor())}; }; std::unique_ptr SymbolIndexer::data; diff --git a/tests/unit/unittest/symbolindexertaskqueue-test.cpp b/tests/unit/unittest/symbolindexertaskqueue-test.cpp index cf337e5e69c..545f19f5b32 100644 --- a/tests/unit/unittest/symbolindexertaskqueue-test.cpp +++ b/tests/unit/unittest/symbolindexertaskqueue-test.cpp @@ -25,7 +25,7 @@ #include "googletest.h" -#include "mocksymbolindexertaskscheduler.h" +#include "mocktaskscheduler.h" #include @@ -50,8 +50,8 @@ MATCHER_P2(IsTask, filePathId, projectPartId, class SymbolIndexerTaskQueue : public testing::Test { protected: - NiceMock mockSymbolIndexerTaskScheduler; - ClangBackEnd::SymbolIndexerTaskQueue queue{mockSymbolIndexerTaskScheduler}; + NiceMock> mockTaskScheduler; + ClangBackEnd::SymbolIndexerTaskQueue queue{mockTaskScheduler}; }; TEST_F(SymbolIndexerTaskQueue, AddTasks) @@ -133,20 +133,20 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndAddTasksInScheduler) {{1, 3}, 1, Callable{}}, {{1, 5}, 1, Callable{}}}); - EXPECT_CALL(mockSymbolIndexerTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); - EXPECT_CALL(mockSymbolIndexerTaskScheduler, addTasks(SizeIs(2))); + EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); + EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(2))); - queue.processTasks(); + queue.processEntries(); } TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndAddTasksWithNoTaskInSchedulerIfTaskAreEmpty) { InSequence s; - EXPECT_CALL(mockSymbolIndexerTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); - EXPECT_CALL(mockSymbolIndexerTaskScheduler, addTasks(IsEmpty())); + EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(2)); + EXPECT_CALL(mockTaskScheduler, addTasks(IsEmpty())); - queue.processTasks(); + queue.processEntries(); } TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndMoveAllTasksInSchedulerIfMoreSlotsAreFree) @@ -156,10 +156,10 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksCallsFreeSlotsAndMoveAllTasksInSchedu {{1, 3}, 1, Callable{}}, {{1, 5}, 1, Callable{}}}); - EXPECT_CALL(mockSymbolIndexerTaskScheduler, freeSlots()).WillRepeatedly(Return(4)); - EXPECT_CALL(mockSymbolIndexerTaskScheduler, addTasks(SizeIs(3))); + EXPECT_CALL(mockTaskScheduler, freeSlots()).WillRepeatedly(Return(4)); + EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(3))); - queue.processTasks(); + queue.processEntries(); } TEST_F(SymbolIndexerTaskQueue, ProcessTasksRemovesProcessedTasks) @@ -167,9 +167,9 @@ TEST_F(SymbolIndexerTaskQueue, ProcessTasksRemovesProcessedTasks) queue.addOrUpdateTasks({{{1, 1}, 1, Callable{}}, {{1, 3}, 1, Callable{}}, {{1, 5}, 1, Callable{}}}); - ON_CALL(mockSymbolIndexerTaskScheduler, freeSlots()).WillByDefault(Return(2)); + ON_CALL(mockTaskScheduler, freeSlots()).WillByDefault(Return(2)); - queue.processTasks(); + queue.processEntries(); ASSERT_THAT(queue.tasks(), SizeIs(1)); } diff --git a/tests/unit/unittest/symbolscollectormanager-test.cpp b/tests/unit/unittest/symbolscollectormanager-test.cpp deleted file mode 100644 index 3a740b1e896..00000000000 --- a/tests/unit/unittest/symbolscollectormanager-test.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** -** -** 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::GeneratedFiles generatedFiles; - ClangBackEnd::SymbolsCollectorManager> manager{database, generatedFiles}; -}; - -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()); -} - -TEST_F(SymbolsCollectorManager, UnusedSystemCollectorIsInitializedWithUnsavedFiles) -{ - auto &collector = manager.unusedSymbolsCollector(); - - ASSERT_TRUE(collector.hasUnsavedFiles); -} - -TEST_F(SymbolsCollectorManager, ReusedSystemCollectorIsInitializedWithUnsavedFiles) -{ - auto &collector = manager.unusedSymbolsCollector(); - collector.setIsUsed(false); - - auto &collector2 = manager.unusedSymbolsCollector(); - - ASSERT_TRUE(collector2.hasUnsavedFiles); -} - -} diff --git a/tests/unit/unittest/symbolindexertaskscheduler-test.cpp b/tests/unit/unittest/taskscheduler-test.cpp similarity index 50% rename from tests/unit/unittest/symbolindexertaskscheduler-test.cpp rename to tests/unit/unittest/taskscheduler-test.cpp index 585102706a6..d6755fa6c71 100644 --- a/tests/unit/unittest/symbolindexertaskscheduler-test.cpp +++ b/tests/unit/unittest/taskscheduler-test.cpp @@ -26,26 +26,29 @@ #include "googletest.h" #include "mocksymbolindexertaskqueue.h" -#include "mocksymbolscollectormanager.h" +#include "mockprocessormanager.h" #include "mocksymbolscollector.h" -#include "mocksymbolstorage.h" -#include "mocksqlitetransactionbackend.h" -#include +#include #include namespace { +using Task = std::function; + +using ClangBackEnd::ProcessorInterface; using ClangBackEnd::SymbolsCollectorInterface; using ClangBackEnd::SymbolStorageInterface; +using NiceMockProcessorManager = NiceMock; +using Scheduler = ClangBackEnd::TaskScheduler; -class SymbolIndexerTaskScheduler : public testing::Test +class TaskScheduler : public testing::Test { protected: void SetUp() { - ON_CALL(mockSymbolsCollectorManager, unusedSymbolsCollector()).WillByDefault(ReturnRef(mockSymbolsCollector)); + ON_CALL(mockProcessorManager, unusedProcessor()).WillByDefault(ReturnRef(mockSymbolsCollector)); } void TearDown() { @@ -55,63 +58,53 @@ protected: protected: MockFunction mock; - ClangBackEnd::SymbolIndexerTaskScheduler::Task call{ - [&] (SymbolsCollectorInterface &, SymbolStorageInterface &, Sqlite::TransactionInterface &) { - mock.Call(); }}; - ClangBackEnd::SymbolIndexerTaskScheduler::Task nocall{ - [&] (SymbolsCollectorInterface &, SymbolStorageInterface &, Sqlite::TransactionInterface &) { - }}; - NiceMock mockSymbolsCollectorManager; + Task call{[&] (ClangBackEnd::ProcessorInterface&) { mock.Call(); }}; + Task nocall{[&] (ClangBackEnd::ProcessorInterface&) {}}; + NiceMockProcessorManager mockProcessorManager; NiceMock mockSymbolsCollector; - MockSymbolStorage mockSymbolStorage; NiceMock mockSymbolIndexerTaskQueue; - MockSqliteTransactionBackend mockSqliteTransactionBackend; - ClangBackEnd::SymbolIndexerTaskScheduler scheduler{mockSymbolsCollectorManager, - mockSymbolStorage, - mockSqliteTransactionBackend, + Scheduler scheduler{mockProcessorManager, mockSymbolIndexerTaskQueue, 4}; - ClangBackEnd::SymbolIndexerTaskScheduler deferedScheduler{mockSymbolsCollectorManager, - mockSymbolStorage, - mockSqliteTransactionBackend, + Scheduler deferredScheduler{mockProcessorManager, mockSymbolIndexerTaskQueue, 4, std::launch::deferred}; }; -TEST_F(SymbolIndexerTaskScheduler, AddTasks) +TEST_F(TaskScheduler, AddTasks) { - deferedScheduler.addTasks({nocall}); + deferredScheduler.addTasks({nocall}); - ASSERT_THAT(deferedScheduler.futures(), SizeIs(1)); + ASSERT_THAT(deferredScheduler.futures(), SizeIs(1)); } -TEST_F(SymbolIndexerTaskScheduler, AddTasksCallsFunction) +TEST_F(TaskScheduler, AddTasksCallsFunction) { EXPECT_CALL(mock, Call()).Times(2); scheduler.addTasks({call, call}); } -TEST_F(SymbolIndexerTaskScheduler, FreeSlots) +TEST_F(TaskScheduler, FreeSlots) { - deferedScheduler.addTasks({nocall, nocall}); + deferredScheduler.addTasks({nocall, nocall}); - auto count = deferedScheduler.freeSlots(); + auto count = deferredScheduler.freeSlots(); ASSERT_THAT(count, 2); } -TEST_F(SymbolIndexerTaskScheduler, ReturnZeroFreeSlotsIfMoreCallsThanCores) +TEST_F(TaskScheduler, ReturnZeroFreeSlotsIfMoreCallsThanCores) { - deferedScheduler.addTasks({nocall, nocall, nocall, nocall, nocall, nocall}); + deferredScheduler.addTasks({nocall, nocall, nocall, nocall, nocall, nocall}); - auto count = deferedScheduler.freeSlots(); + auto count = deferredScheduler.freeSlots(); ASSERT_THAT(count, 0); } -TEST_F(SymbolIndexerTaskScheduler, FreeSlotsAfterFinishing) +TEST_F(TaskScheduler, FreeSlotsAfterFinishing) { scheduler.addTasks({nocall, nocall}); scheduler.syncTasks(); @@ -121,7 +114,7 @@ TEST_F(SymbolIndexerTaskScheduler, FreeSlotsAfterFinishing) ASSERT_THAT(count, 4); } -TEST_F(SymbolIndexerTaskScheduler, NoFuturesAfterFreeSlots) +TEST_F(TaskScheduler, NoFuturesAfterFreeSlots) { scheduler.addTasks({nocall, nocall}); scheduler.syncTasks(); @@ -131,41 +124,35 @@ TEST_F(SymbolIndexerTaskScheduler, NoFuturesAfterFreeSlots) ASSERT_THAT(scheduler.futures(), IsEmpty()); } -TEST_F(SymbolIndexerTaskScheduler, FreeSlotsCallSymbolsCollectorSetIsUnused) +TEST_F(TaskScheduler, FreeSlotsCallsCleanupMethodsAfterTheWorkIsDone) { - InSequence s; scheduler.addTasks({nocall, nocall}); scheduler.syncTasks(); + InSequence s; - EXPECT_CALL(mockSymbolsCollector, setIsUsed(false)).Times(2); + EXPECT_CALL(mockSymbolsCollector, doInMainThreadAfterFinished()); + EXPECT_CALL(mockSymbolsCollector, setIsUsed(false)); + EXPECT_CALL(mockSymbolsCollector, clear()); + EXPECT_CALL(mockSymbolsCollector, doInMainThreadAfterFinished()); + EXPECT_CALL(mockSymbolsCollector, setIsUsed(false)); + EXPECT_CALL(mockSymbolsCollector, clear()); scheduler.freeSlots(); } -TEST_F(SymbolIndexerTaskScheduler, FreeSlotsCallClearsSymbolsCollector) +TEST_F(TaskScheduler, AddTaskCallSymbolsCollectorManagerUnusedSymbolsCollector) { - 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); + EXPECT_CALL(mockProcessorManager, unusedProcessor()).Times(2); scheduler.addTasks({nocall, nocall}); } -TEST_F(SymbolIndexerTaskScheduler, CallProcessTasksInQueueAfterFinishedTasks) +TEST_F(TaskScheduler, CallProcessTasksInQueueAfterFinishedTasks) { InSequence s; EXPECT_CALL(mock, Call()); - EXPECT_CALL(mockSymbolIndexerTaskQueue, processTasks()); + EXPECT_CALL(mockSymbolIndexerTaskQueue, processEntries()); scheduler.addTasks({call}); scheduler.syncTasks(); diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index 09d1083a22d..9f63ed748d0 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -59,7 +59,6 @@ SOURCES += \ locatorfilter-test.cpp \ matchingtext-test.cpp \ mimedatabase-utilities.cpp \ - pchgenerator-test.cpp \ pchmanagerclientserverinprocess-test.cpp \ pchmanagerclient-test.cpp \ pchmanagerserver-test.cpp \ @@ -99,9 +98,10 @@ SOURCES += \ generatedfiles-test.cpp \ sourcesmanager-test.cpp \ symbolindexertaskqueue-test.cpp \ - symbolindexertaskscheduler-test.cpp \ - symbolscollectormanager-test.cpp \ - refactoringprojectupdater-test.cpp + refactoringprojectupdater-test.cpp \ + projectpartqueue-test.cpp \ + processormanager-test.cpp \ + taskscheduler-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ @@ -203,7 +203,6 @@ HEADERS += \ mockclangpathwatcher.h \ mockclangpathwatchernotifier.h \ mockpchcreator.h \ - mockpchgeneratornotifier.h \ mockpchmanagerclient.h \ mockpchmanagernotifier.h \ mockpchmanagerserver.h \ @@ -238,11 +237,14 @@ HEADERS += \ mockprojectpartprovider.h \ mockprecompiledheaderstorage.h \ mockeditormanager.h \ - mocksymbolscollectormanager.h \ mocksymbolindexertaskqueue.h \ - mocksymbolindexertaskscheduler.h \ mockcppmodelmanager.h \ - mockgeneratedfiles.h + mockgeneratedfiles.h \ + mockqueue.h \ + mockprojectpartqueue.h \ + mockprocessor.h \ + mockprocessormanager.h \ + mocktaskscheduler.h !isEmpty(LIBCLANG_LIBS) { HEADERS += \