diff options
author | Marco Bubke <marco.bubke@qt.io> | 2018-12-17 12:06:57 +0100 |
---|---|---|
committer | Marco Bubke <marco.bubke@qt.io> | 2019-01-21 15:27:10 +0000 |
commit | dd366b68dea11eebb0b1c53f3cff1902ce2bfefa (patch) | |
tree | b919ffd70c5e3677244d2475381f6fb8defdd3eb | |
parent | a78e3e5dd5f882a28a3152f2e63ae986a9f2a8c5 (diff) |
PchManager: Split pch tasks in project and system pch tasks
Like you can see in the task numbers this patch is touching many different
areas. So I will only touch the main parts. It is using a clang action
instead of an extra process which will be enabling the handling of
generated files in PCHs. The flags from the project part are now not
anymore transformed in a command line but they are saved in the container
semantically aware so that they can later be merged. Most of this patch is
simply polishing of other patches.
Task-number: QTCREATORBUG-21346
Task-number: QTCREATORBUG-21380
Task-number: QTCREATORBUG-21382
Task-number: QTCREATORBUG-21383
Task-number: QTCREATORBUG-21693
Task-number: QTCREATORBUG-21778
Change-Id: I9b0c02d8149b554254e819448fbc61eeaa5b7494
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
114 files changed, 3748 insertions, 1793 deletions
diff --git a/src/libs/clangsupport/clangsupport-lib.pri b/src/libs/clangsupport/clangsupport-lib.pri index 03713650ad..221ccfd001 100644 --- a/src/libs/clangsupport/clangsupport-lib.pri +++ b/src/libs/clangsupport/clangsupport-lib.pri @@ -44,7 +44,6 @@ SOURCES += \ $$PWD/pchmanagerserverinterface.cpp \ $$PWD/pchmanagerserverproxy.cpp \ $$PWD/precompiledheadersupdatedmessage.cpp \ - $$PWD/projectpartcontainerv2.cpp \ $$PWD/projectpartpch.cpp \ $$PWD/readmessageblock.cpp \ $$PWD/refactoringclientinterface.cpp \ @@ -87,7 +86,8 @@ SOURCES += \ $$PWD/baseserverproxy.cpp \ $$PWD/updategeneratedfilesmessage.cpp \ $$PWD/removegeneratedfilesmessage.cpp \ - $$PWD/generatedfiles.cpp + $$PWD/generatedfiles.cpp \ + $$PWD/projectpartcontainer.cpp HEADERS += \ $$PWD/cancelmessage.h \ @@ -138,7 +138,6 @@ HEADERS += \ $$PWD/pchmanagerserverinterface.h \ $$PWD/pchmanagerserverproxy.h \ $$PWD/precompiledheadersupdatedmessage.h \ - $$PWD/projectpartcontainerv2.h \ $$PWD/projectpartpch.h \ $$PWD/readmessageblock.h \ $$PWD/refactoringclientinterface.h \ @@ -205,6 +204,9 @@ HEADERS += \ $$PWD/generatedfiles.h \ $$PWD/generatedfilesinterface.h \ $$PWD/progressmessage.h \ - $$PWD/progresscounter.h + $$PWD/progresscounter.h \ + $$PWD/includesearchpath.h \ + $$PWD/commandlinebuilder.h \ + $$PWD/projectpartcontainer.h contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols diff --git a/src/libs/clangsupport/commandlinebuilder.h b/src/libs/clangsupport/commandlinebuilder.h new file mode 100644 index 0000000000..af9c0f1baf --- /dev/null +++ b/src/libs/clangsupport/commandlinebuilder.h @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** 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 "filepathview.h" + +#include <compilermacro.h> +#include <includesearchpath.h> + +#include <utils/smallstringvector.h> +#include <utils/cpplanguage_details.h> + +namespace ClangBackEnd { + +template<typename ProjectInfo, typename OutputContainer = std::vector<std::string>> +class CommandLineBuilder +{ +public: + CommandLineBuilder(const ProjectInfo &projectInfo, + const Utils::SmallStringVector &toolChainArguments = {}, + FilePathView sourcePath = {}, + FilePathView outputPath = {}, + FilePathView includePchPath = {}) + { + commandLine.reserve(128); + + addCompiler(projectInfo.language); + addToolChainArguments(toolChainArguments); + addLanguage(projectInfo); + addLanguageVersion(projectInfo); + addNoStdIncAndNoStdLibInc(); + addProjectIncludeSearchPaths( + sortedIncludeSearchPaths(projectInfo.projectIncludeSearchPaths)); + addSystemAndBuiltInIncludeSearchPaths( + sortedIncludeSearchPaths(projectInfo.systemIncludeSearchPaths)); + addIncludePchPath(includePchPath); + addOutputPath(outputPath); + addSourcePath(sourcePath); + } + + void addCompiler(Utils::Language language) + { + if (language == Utils::Language::Cxx) + commandLine.emplace_back("clang++"); + else + commandLine.emplace_back("clang"); + } + + void addToolChainArguments(const Utils::SmallStringVector &toolChainArguments) + { + for (Utils::SmallStringView argument : toolChainArguments) + commandLine.emplace_back(argument); + } + + static const char *language(const ProjectInfo &projectInfo) + { + switch (projectInfo.language) { + case Utils::Language::C: + if (projectInfo.languageExtension && Utils::LanguageExtension::ObjectiveC) + return "objective-c-header"; + + return "c-header"; + case Utils::Language::Cxx: + if (projectInfo.languageExtension && Utils::LanguageExtension::ObjectiveC) + return "objective-c++-header"; + } + + return "c++-header"; + } + + void addLanguage(const ProjectInfo &projectInfo) + { + commandLine.emplace_back("-x"); + commandLine.emplace_back(language(projectInfo)); + } + + const char *standardLanguageVersion(Utils::LanguageVersion languageVersion) + { + switch (languageVersion) { + case Utils::LanguageVersion::C89: + return "-std=c89"; + case Utils::LanguageVersion::C99: + return "-std=c99"; + case Utils::LanguageVersion::C11: + return "-std=c11"; + case Utils::LanguageVersion::C18: + return "-std=c18"; + case Utils::LanguageVersion::CXX98: + return "-std=c++98"; + case Utils::LanguageVersion::CXX03: + return "-std=c++03"; + case Utils::LanguageVersion::CXX11: + return "-std=c++11"; + case Utils::LanguageVersion::CXX14: + return "-std=c++14"; + case Utils::LanguageVersion::CXX17: + return "-std=c++17"; + case Utils::LanguageVersion::CXX2a: + return "-std=c++2a"; + } + + return "-std=c++2a"; + } + + const char *gnuLanguageVersion(Utils::LanguageVersion languageVersion) + { + switch (languageVersion) { + case Utils::LanguageVersion::C89: + return "-std=gnu89"; + case Utils::LanguageVersion::C99: + return "-std=gnu99"; + case Utils::LanguageVersion::C11: + return "-std=gnu11"; + case Utils::LanguageVersion::C18: + return "-std=gnu18"; + case Utils::LanguageVersion::CXX98: + return "-std=gnu++98"; + case Utils::LanguageVersion::CXX03: + return "-std=gnu++03"; + case Utils::LanguageVersion::CXX11: + return "-std=gnu++11"; + case Utils::LanguageVersion::CXX14: + return "-std=gnu++14"; + case Utils::LanguageVersion::CXX17: + return "-std=gnu++17"; + case Utils::LanguageVersion::CXX2a: + return "-std=gnu++2a"; + } + + return "-std=gnu++2a"; + } + + const char *includeOption(IncludeSearchPathType type) + { + switch (type) { + case IncludeSearchPathType::User: + case IncludeSearchPathType::System: + case IncludeSearchPathType::BuiltIn: + return "-isystem"; + case IncludeSearchPathType::Framework: + return "-F"; + case IncludeSearchPathType::Invalid: + return ""; + } + + return "-I"; + } + + void addLanguageVersion(const ProjectInfo &projectInfo) + { + if (projectInfo.languageExtension && Utils::LanguageExtension::Gnu) + commandLine.emplace_back(gnuLanguageVersion(projectInfo.languageVersion)); + else + commandLine.emplace_back(standardLanguageVersion(projectInfo.languageVersion)); + } + + IncludeSearchPaths sortedIncludeSearchPaths(const IncludeSearchPaths &unsortedPaths) + { + IncludeSearchPaths paths = unsortedPaths; + std::sort(paths.begin(), paths.end(), [](const auto &first, const auto &second) { + return first.index < second.index; + }); + + return paths; + } + + void addProjectIncludeSearchPaths(const IncludeSearchPaths &projectIncludeSearchPaths) + { + for (const IncludeSearchPath &path : projectIncludeSearchPaths) { + commandLine.emplace_back("-I"); + commandLine.emplace_back(path.path); + } + } + + void addSystemAndBuiltInIncludeSearchPaths(const IncludeSearchPaths &systemIncludeSearchPaths) + { + addSystemIncludeSearchPaths(systemIncludeSearchPaths); + addBuiltInSystemSearchPaths(systemIncludeSearchPaths); + } + + void addSystemIncludeSearchPaths(const IncludeSearchPaths &systemIncludeSearchPaths) + { + for (const IncludeSearchPath &path : systemIncludeSearchPaths) { + if (path.type != IncludeSearchPathType::BuiltIn) { + commandLine.emplace_back(includeOption(path.type)); + commandLine.emplace_back(path.path); + } + } + } + + void addBuiltInSystemSearchPaths(const IncludeSearchPaths &systemIncludeSearchPaths) + { + for (const IncludeSearchPath &path : systemIncludeSearchPaths) { + if (path.type == IncludeSearchPathType::BuiltIn) { + commandLine.emplace_back(includeOption(path.type)); + commandLine.emplace_back(path.path); + } + } + } + + void addOutputPath(FilePathView outputPath) + { + if (!outputPath.isEmpty()) { + commandLine.emplace_back("-o"); + commandLine.emplace_back(outputPath); + } + } + + void addSourcePath(FilePathView sourcePath) + { + if (!sourcePath.isEmpty()) + commandLine.emplace_back(sourcePath); + } + + void addIncludePchPath(FilePathView includePchPath) + { + if (!includePchPath.isEmpty()) { + commandLine.emplace_back("-Xclang"); + commandLine.emplace_back("-include-pch"); + commandLine.emplace_back("-Xclang"); + commandLine.emplace_back(includePchPath); + } + } + + void addNoStdIncAndNoStdLibInc() + { + commandLine.emplace_back("-nostdinc"); + commandLine.emplace_back("-nostdlibinc"); + } + +public: + OutputContainer commandLine; +}; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/filepath.h b/src/libs/clangsupport/filepath.h index 9ff019de76..e08f3f4996 100644 --- a/src/libs/clangsupport/filepath.h +++ b/src/libs/clangsupport/filepath.h @@ -51,6 +51,14 @@ public: m_slashIndex = view.slashIndex(); } + explicit FilePath(Utils::SmallStringView &&filePath) + : Utils::PathString(filePath) + { + FilePathView view{*this}; + + m_slashIndex = view.slashIndex(); + } + FilePath(FilePathView filePathView) : Utils::PathString(filePathView.toStringView()), m_slashIndex(filePathView.slashIndex()) diff --git a/src/libs/clangsupport/filepathview.h b/src/libs/clangsupport/filepathview.h index 27dac8377f..09b940fa61 100644 --- a/src/libs/clangsupport/filepathview.h +++ b/src/libs/clangsupport/filepathview.h @@ -37,6 +37,7 @@ template <char WindowsSlash> class AbstractFilePathView : public Utils::SmallStringView { public: + constexpr AbstractFilePathView() = default; explicit AbstractFilePathView(const char *const string, const size_type size) noexcept : Utils::SmallStringView(string, size), m_slashIndex(lastSlashIndex(*this)) diff --git a/src/libs/clangsupport/includesearchpath.h b/src/libs/clangsupport/includesearchpath.h new file mode 100644 index 0000000000..239af9c1a4 --- /dev/null +++ b/src/libs/clangsupport/includesearchpath.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** 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 <utils/smallstringio.h> + +#include <QDataStream> + +#include <vector> + +namespace ClangBackEnd { + +enum class IncludeSearchPathType : unsigned char { + Invalid, + User, + BuiltIn, + System, + Framework, +}; + +class IncludeSearchPath +{ +public: + IncludeSearchPath() = default; + IncludeSearchPath(Utils::PathString &&path, int index, IncludeSearchPathType type) + : path(std::move(path)) + , index(index) + , type(type) + {} + + IncludeSearchPath(Utils::PathString &&path, int index, int type) + : path(std::move(path)) + , index(index) + , type(static_cast<IncludeSearchPathType>(type)) + {} + + friend QDataStream &operator<<(QDataStream &out, const IncludeSearchPath &includeSearchPath) + { + out << includeSearchPath.path; + out << includeSearchPath.index; + out << static_cast<unsigned char>(includeSearchPath.type); + + return out; + } + + friend QDataStream &operator>>(QDataStream &in, IncludeSearchPath &includeSearchPath) + { + unsigned char type; + + in >> includeSearchPath.path; + in >> includeSearchPath.index; + in >> type; + + includeSearchPath.type = static_cast<IncludeSearchPathType>(type); + + return in; + } + + friend bool operator==(const IncludeSearchPath &first, const IncludeSearchPath &second) + { + return std::tie(first.type, first.index, first.path) + == std::tie(second.type, second.index, second.path); + } + + friend bool operator<(const IncludeSearchPath &first, const IncludeSearchPath &second) + { + return std::tie(first.path, first.index, first.type) + < std::tie(second.path, second.index, second.type); + } + +public: + Utils::PathString path; + int index = -1; + IncludeSearchPathType type = IncludeSearchPathType::Invalid; +}; + +using IncludeSearchPaths = std::vector<IncludeSearchPath>; + +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/progresscounter.h b/src/libs/clangsupport/progresscounter.h index 1958f6ef8c..fbdc9dda45 100644 --- a/src/libs/clangsupport/progresscounter.h +++ b/src/libs/clangsupport/progresscounter.h @@ -40,23 +40,29 @@ public: void addTotal(int total) { - m_total += total; + if (total) { + m_total += total; - m_progressCallback(m_progress, m_total); + m_progressCallback(m_progress, m_total); + } } void removeTotal(int total) { - m_total -= total; + if (total) { + m_total -= total; - sendProgress(); + sendProgress(); + } } void addProgress(int progress) { - m_progress += progress; + if (progress) { + m_progress += progress; - sendProgress(); + sendProgress(); + } } void sendProgress() diff --git a/src/libs/clangsupport/projectpartcontainerv2.cpp b/src/libs/clangsupport/projectpartcontainer.cpp index 7d03f9486d..a51e927db5 100644 --- a/src/libs/clangsupport/projectpartcontainerv2.cpp +++ b/src/libs/clangsupport/projectpartcontainer.cpp @@ -23,22 +23,19 @@ ** ****************************************************************************/ -#include "projectpartcontainerv2.h" +#include "projectpartcontainer.h" namespace ClangBackEnd { -namespace V2 { QDebug operator<<(QDebug debug, const ProjectPartContainer &container) { debug.nospace() << "ProjectPartContainer(" << container.projectPartId << "," - << container.arguments << ", " + << container.toolChainArguments << ", " << container.headerPathIds << ", " << container.sourcePathIds << ")"; return debug; } - -} // namespace V2 } // namespace ClangBackEnd diff --git a/src/libs/clangsupport/projectpartcontainer.h b/src/libs/clangsupport/projectpartcontainer.h new file mode 100644 index 0000000000..d805ef5aad --- /dev/null +++ b/src/libs/clangsupport/projectpartcontainer.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** 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 "clangsupport_global.h" + +#include "compilermacro.h" +#include "filepathid.h" +#include "includesearchpath.h" + +#include <utils/cpplanguage_details.h> +#include <utils/smallstringio.h> + +namespace ClangBackEnd { + +class ProjectPartContainer +{ + using uchar = unsigned char; +public: + ProjectPartContainer() = default; + ProjectPartContainer(Utils::SmallString &&projectPartId, + Utils::SmallStringVector &&arguments, + CompilerMacros &&compilerMacros, + IncludeSearchPaths &&systemIncludeSearchPaths, + IncludeSearchPaths &&projectIncludeSearchPaths, + FilePathIds &&headerPathIds, + FilePathIds &&sourcePathIds, + Utils::Language language, + Utils::LanguageVersion languageVersion, + Utils::LanguageExtension languageExtension) + : projectPartId(std::move(projectPartId)) + , toolChainArguments(std::move(arguments)) + , compilerMacros(std::move(compilerMacros)) + , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) + , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) + , headerPathIds(std::move(headerPathIds)) + , sourcePathIds(std::move(sourcePathIds)) + , language(language) + , languageVersion(languageVersion) + , languageExtension(languageExtension) + { + } + + friend QDataStream &operator<<(QDataStream &out, const ProjectPartContainer &container) + { + out << container.projectPartId; + out << container.toolChainArguments; + out << container.compilerMacros; + out << container.systemIncludeSearchPaths; + out << container.projectIncludeSearchPaths; + out << container.headerPathIds; + out << container.sourcePathIds; + out << uchar(container.language); + out << uchar(container.languageVersion); + out << uchar(container.languageExtension); + return out; + } + + friend QDataStream &operator>>(QDataStream &in, ProjectPartContainer &container) + { + uchar language; + uchar languageVersion; + uchar languageExtension; + + in >> container.projectPartId; + in >> container.toolChainArguments; + in >> container.compilerMacros; + in >> container.systemIncludeSearchPaths; + in >> container.projectIncludeSearchPaths; + in >> container.headerPathIds; + in >> container.sourcePathIds; + in >> language; + in >> languageVersion; + in >> languageExtension; + + container.language = static_cast<Utils::Language>(language); + container.languageVersion = static_cast<Utils::LanguageVersion>(languageVersion); + container.languageExtension = static_cast<Utils::LanguageExtension>(languageExtension); + + return in; + } + + friend bool operator==(const ProjectPartContainer &first, const ProjectPartContainer &second) + { + return first.projectPartId == second.projectPartId + && first.toolChainArguments == second.toolChainArguments + && first.compilerMacros == second.compilerMacros + && first.systemIncludeSearchPaths == second.systemIncludeSearchPaths + && first.projectIncludeSearchPaths == second.projectIncludeSearchPaths + && first.headerPathIds == second.headerPathIds + && first.sourcePathIds == second.sourcePathIds&& first.language == second.language + && first.languageVersion == second.languageVersion + && first.languageExtension == second.languageExtension; + } + + friend bool operator<(const ProjectPartContainer &first, const ProjectPartContainer &second) + { + return std::tie(first.projectPartId, + first.toolChainArguments, + first.compilerMacros, + first.systemIncludeSearchPaths, + first.projectIncludeSearchPaths, + first.headerPathIds, + first.sourcePathIds, + first.language, + first.languageVersion, + first.languageExtension) + < std::tie(second.projectPartId, + second.toolChainArguments, + second.compilerMacros, + second.systemIncludeSearchPaths, + second.projectIncludeSearchPaths, + second.headerPathIds, + second.sourcePathIds, + second.language, + second.languageVersion, + second.languageExtension); + } + + ProjectPartContainer clone() const + { + return *this; + } + +public: + Utils::SmallString projectPartId; + Utils::SmallStringVector toolChainArguments; + CompilerMacros compilerMacros; + IncludeSearchPaths systemIncludeSearchPaths; + IncludeSearchPaths projectIncludeSearchPaths; + FilePathIds headerPathIds; + FilePathIds sourcePathIds; + Utils::Language language = Utils::Language::Cxx; + Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98; + Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None; +}; + +using ProjectPartContainers = std::vector<ProjectPartContainer>; + +QDebug operator<<(QDebug debug, const ProjectPartContainer &container); +} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/projectpartcontainerv2.h b/src/libs/clangsupport/projectpartcontainerv2.h deleted file mode 100644 index be21ad874f..0000000000 --- a/src/libs/clangsupport/projectpartcontainerv2.h +++ /dev/null @@ -1,125 +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 "clangsupport_global.h" - -#include "compilermacro.h" -#include "filepathid.h" - -#include <utils/smallstringio.h> - -namespace ClangBackEnd { -namespace V2 { - -class ProjectPartContainer -{ -public: - ProjectPartContainer() = default; - ProjectPartContainer(Utils::SmallString &&projectPartId, - Utils::SmallStringVector &&arguments, - CompilerMacros &&compilerMacros, - Utils::SmallStringVector &&includeSearchPaths, - FilePathIds &&headerPathIds, - FilePathIds &&sourcePathIds) - : projectPartId(std::move(projectPartId)), - arguments(std::move(arguments)), - compilerMacros(std::move(compilerMacros)), - includeSearchPaths(std::move(includeSearchPaths)), - headerPathIds(std::move(headerPathIds)), - sourcePathIds(std::move(sourcePathIds)) - { - } - - friend QDataStream &operator<<(QDataStream &out, const ProjectPartContainer &container) - { - out << container.projectPartId; - out << container.arguments; - out << container.compilerMacros; - out << container.includeSearchPaths; - out << container.headerPathIds; - out << container.sourcePathIds; - - return out; - } - - friend QDataStream &operator>>(QDataStream &in, ProjectPartContainer &container) - { - in >> container.projectPartId; - in >> container.arguments; - in >> container.compilerMacros; - in >> container.includeSearchPaths; - in >> container.headerPathIds; - in >> container.sourcePathIds; - - return in; - } - - friend bool operator==(const ProjectPartContainer &first, const ProjectPartContainer &second) - { - return first.projectPartId == second.projectPartId - && first.arguments == second.arguments - && first.compilerMacros == second.compilerMacros - && first.includeSearchPaths == second.includeSearchPaths - && first.headerPathIds == second.headerPathIds - && first.sourcePathIds == second.sourcePathIds; - } - - friend bool operator<(const ProjectPartContainer &first, const ProjectPartContainer &second) - { - return std::tie(first.projectPartId, - first.arguments, - first.compilerMacros, - first.includeSearchPaths, - first.headerPathIds, - first.sourcePathIds) - < std::tie(second.projectPartId, - second.arguments, - second.compilerMacros, - first.includeSearchPaths, - second.headerPathIds, - second.sourcePathIds); - } - - ProjectPartContainer clone() const - { - return *this; - } - -public: - Utils::SmallString projectPartId; - Utils::SmallStringVector arguments; - CompilerMacros compilerMacros; - Utils::SmallStringVector includeSearchPaths; - FilePathIds headerPathIds; - FilePathIds sourcePathIds; -}; - -using ProjectPartContainers = std::vector<ProjectPartContainer>; - -QDebug operator<<(QDebug debug, const ProjectPartContainer &container); -} // namespace V2 -} // namespace ClangBackEnd diff --git a/src/libs/clangsupport/projectpartpch.h b/src/libs/clangsupport/projectpartpch.h index 6048a0b2f0..a413915b76 100644 --- a/src/libs/clangsupport/projectpartpch.h +++ b/src/libs/clangsupport/projectpartpch.h @@ -28,6 +28,7 @@ #include "clangsupport_global.h" #include <utils/smallstringio.h> +#include <filepath.h> namespace ClangBackEnd { @@ -36,15 +37,16 @@ class ProjectPartPch public: ProjectPartPch() = default; ProjectPartPch(Utils::SmallString &&projectPartId, - Utils::SmallString &&pchPath, + FilePath &&pchPath, long long lastModified) : projectPartId(std::move(projectPartId)), pchPath(std::move(pchPath)), lastModified(lastModified) {} + ProjectPartPch(Utils::SmallStringView pchPath, long long lastModified) - : pchPath(pchPath), + : pchPath(FilePathView(pchPath)), lastModified(lastModified) {} @@ -78,7 +80,7 @@ public: public: Utils::SmallString projectPartId; - Utils::SmallString pchPath; + FilePath pchPath; long long lastModified = -1; }; diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index 94665409fe..44c23e18a0 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -125,7 +125,8 @@ public: const Sqlite::Column &projectPartNameColumn = table.addColumn("projectPartName", Sqlite::ColumnType::Text); table.addColumn("compilerArguments", Sqlite::ColumnType::Text); table.addColumn("compilerMacros", Sqlite::ColumnType::Text); - table.addColumn("includeSearchPaths", Sqlite::ColumnType::Text); + table.addColumn("systemIncludeSearchPaths", Sqlite::ColumnType::Text); + table.addColumn("projectIncludeSearchPaths", Sqlite::ColumnType::Text); table.addUniqueIndex({projectPartNameColumn}); table.initialize(database); diff --git a/src/libs/clangsupport/removeprojectpartsmessage.h b/src/libs/clangsupport/removeprojectpartsmessage.h index 1f45cc5f52..0aea092fea 100644 --- a/src/libs/clangsupport/removeprojectpartsmessage.h +++ b/src/libs/clangsupport/removeprojectpartsmessage.h @@ -25,7 +25,7 @@ #pragma once -#include "projectpartcontainerv2.h" +#include "projectpartcontainer.h" namespace ClangBackEnd { diff --git a/src/libs/clangsupport/updateprojectpartsmessage.h b/src/libs/clangsupport/updateprojectpartsmessage.h index e923d7ba03..b1c6ca1f61 100644 --- a/src/libs/clangsupport/updateprojectpartsmessage.h +++ b/src/libs/clangsupport/updateprojectpartsmessage.h @@ -26,7 +26,7 @@ #pragma once #include "filecontainerv2.h" -#include "projectpartcontainerv2.h" +#include "projectpartcontainer.h" namespace ClangBackEnd { @@ -34,11 +34,13 @@ class UpdateProjectPartsMessage { public: UpdateProjectPartsMessage() = default; - UpdateProjectPartsMessage(V2::ProjectPartContainers &&projectsParts) + UpdateProjectPartsMessage(ProjectPartContainers &&projectsParts, + Utils::SmallStringVector &&toolChainArguments) : projectsParts(std::move(projectsParts)) + , toolChainArguments(toolChainArguments) {} - V2::ProjectPartContainers takeProjectsParts() + ProjectPartContainers takeProjectsParts() { return std::move(projectsParts); } @@ -46,6 +48,7 @@ public: friend QDataStream &operator<<(QDataStream &out, const UpdateProjectPartsMessage &message) { out << message.projectsParts; + out << message.toolChainArguments; return out; } @@ -53,6 +56,7 @@ public: friend QDataStream &operator>>(QDataStream &in, UpdateProjectPartsMessage &message) { in >> message.projectsParts; + in >> message.toolChainArguments; return in; } @@ -60,7 +64,8 @@ public: friend bool operator==(const UpdateProjectPartsMessage &first, const UpdateProjectPartsMessage &second) { - return first.projectsParts == second.projectsParts; + return first.projectsParts == second.projectsParts + && first.toolChainArguments == second.toolChainArguments; } UpdateProjectPartsMessage clone() const @@ -69,7 +74,8 @@ public: } public: - V2::ProjectPartContainers projectsParts; + ProjectPartContainers projectsParts; + Utils::SmallStringVector toolChainArguments; }; CLANGSUPPORT_EXPORT QDebug operator<<(QDebug debug, const UpdateProjectPartsMessage &message); diff --git a/src/libs/utils/cpplanguage_details.h b/src/libs/utils/cpplanguage_details.h index 1853d8ed0a..a4defb3262 100644 --- a/src/libs/utils/cpplanguage_details.h +++ b/src/libs/utils/cpplanguage_details.h @@ -60,4 +60,16 @@ enum class LanguageExtension : unsigned char { Q_DECLARE_FLAGS(LanguageExtensions, LanguageExtension) +constexpr enum LanguageExtension operator|(const LanguageExtension first, + const LanguageExtension second) +{ + return static_cast<LanguageExtension>( + (static_cast<unsigned char>(first) | static_cast<unsigned char>(second))); +} + +constexpr bool operator&&(const LanguageExtension first, const LanguageExtension second) +{ + return static_cast<unsigned char>(first) & static_cast<unsigned char>(second); +} + } // namespace Utils diff --git a/src/plugins/clangpchmanager/projectupdater.cpp b/src/plugins/clangpchmanager/projectupdater.cpp index a2c97c9d14..74b63a8f1a 100644 --- a/src/plugins/clangpchmanager/projectupdater.cpp +++ b/src/plugins/clangpchmanager/projectupdater.cpp @@ -36,6 +36,7 @@ #include <cpptools/compileroptionsbuilder.h> #include <cpptools/projectpart.h> +#include <cpptools/headerpathfilter.h> #include <utils/algorithm.h> @@ -64,10 +65,11 @@ ProjectUpdater::ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &s { } -void ProjectUpdater::updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts) +void ProjectUpdater::updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts, + Utils::SmallStringVector &&toolChainArguments) { - m_server.updateProjectParts( - ClangBackEnd::UpdateProjectPartsMessage{toProjectPartContainers(projectParts)}); + m_server.updateProjectParts(ClangBackEnd::UpdateProjectPartsMessage{ + toProjectPartContainers(projectParts), std::move(toolChainArguments)}); } void ProjectUpdater::removeProjectParts(const QStringList &projectPartIds) @@ -147,11 +149,21 @@ HeaderAndSources ProjectUpdater::headerAndSourcesFromProjectPart( return headerAndSources; } -QStringList ProjectUpdater::compilerArguments(CppTools::ProjectPart *projectPart) +QStringList ProjectUpdater::toolChainArguments(CppTools::ProjectPart *projectPart) { using CppTools::CompilerOptionsBuilder; CompilerOptionsBuilder builder(*projectPart, CppTools::UseSystemHeader::Yes); - return builder.build(CppTools::ProjectFile::CXXHeader, CppTools::UsePrecompiledHeaders::No); + + builder.addWordWidth(); + builder.addPicIfCompilerFlagsContainsIt(); + builder.addTargetTriple(); + builder.addExtraCodeModelFlags(); + builder.undefineClangVersionMacrosForMsvc(); + builder.undefineCppLanguageFeatureMacrosForMsvc2015(); + builder.addProjectConfigFileInclude(); + builder.addMsvcCompatibilityVersion(); + + return builder.options(); } ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(const ProjectExplorer::Macros &projectMacros) @@ -167,43 +179,102 @@ ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(const ProjectE return macros; } -Utils::SmallStringVector ProjectUpdater::createIncludeSearchPaths( - const ProjectExplorer::HeaderPaths &projectPartHeaderPaths) +namespace { +ClangBackEnd::IncludeSearchPathType convertType(ProjectExplorer::HeaderPathType sourceType) { - Utils::SmallStringVector includePaths; - - for (const ProjectExplorer::HeaderPath &projectPartHeaderPath : projectPartHeaderPaths) { - if (!projectPartHeaderPath.path.isEmpty()) - includePaths.emplace_back(projectPartHeaderPath.path); + using ProjectExplorer::HeaderPathType; + using ClangBackEnd::IncludeSearchPathType; + + switch (sourceType) { + case HeaderPathType::User: + return IncludeSearchPathType::User; + case HeaderPathType::System: + return IncludeSearchPathType::System; + case HeaderPathType::BuiltIn: + return IncludeSearchPathType::BuiltIn; + case HeaderPathType::Framework: + return IncludeSearchPathType::Framework; } - std::sort(includePaths.begin(), includePaths.end()); + return IncludeSearchPathType::Invalid; +} + +ClangBackEnd::IncludeSearchPaths convertToIncludeSearchPaths(ProjectExplorer::HeaderPaths headerPaths) +{ + ClangBackEnd::IncludeSearchPaths paths; + paths.reserve(Utils::usize(headerPaths)); + + int index = 0; + for (const ProjectExplorer::HeaderPath &headerPath : headerPaths) + paths.emplace_back(headerPath.path, ++index, convertType(headerPath.type)); + + std::sort(paths.begin(), paths.end()); + + return paths; +} - return includePaths; +ClangBackEnd::IncludeSearchPaths convertToIncludeSearchPaths( + ProjectExplorer::HeaderPaths headerPaths, ProjectExplorer::HeaderPaths headerPaths2) +{ + ClangBackEnd::IncludeSearchPaths paths; + paths.reserve(Utils::usize(headerPaths) + Utils::usize(headerPaths2)); + + int index = 0; + for (const ProjectExplorer::HeaderPath &headerPath : headerPaths) + paths.emplace_back(headerPath.path, ++index, convertType(headerPath.type)); + + for (const ProjectExplorer::HeaderPath &headerPath : headerPaths2) + paths.emplace_back(headerPath.path, ++index, convertType(headerPath.type)); + + std::sort(paths.begin(), paths.end()); + + return paths; +} + +} // namespace + +ProjectUpdater::SystemAndProjectIncludeSearchPaths ProjectUpdater::createIncludeSearchPaths( + const CppTools::ProjectPart &projectPart) +{ + CppTools::HeaderPathFilter filter(projectPart, + CppTools::UseTweakedHeaderPaths::Yes, + CLANG_VERSION, + CLANG_RESOURCE_DIR); + filter.process(); + + return {convertToIncludeSearchPaths(filter.systemHeaderPaths, filter.builtInHeaderPaths), + convertToIncludeSearchPaths(filter.userHeaderPaths)}; } -ClangBackEnd::V2::ProjectPartContainer ProjectUpdater::toProjectPartContainer( +ClangBackEnd::ProjectPartContainer ProjectUpdater::toProjectPartContainer( CppTools::ProjectPart *projectPart) const { - QStringList arguments = compilerArguments(projectPart); + QStringList arguments = toolChainArguments(projectPart); HeaderAndSources headerAndSources = headerAndSourcesFromProjectPart(projectPart); - return ClangBackEnd::V2::ProjectPartContainer(projectPart->id(), - Utils::SmallStringVector(arguments), - createCompilerMacros(projectPart->projectMacros), - createIncludeSearchPaths(projectPart->headerPaths), - std::move(headerAndSources.headers), - std::move(headerAndSources.sources)); + auto includeSearchPaths = createIncludeSearchPaths(*projectPart); + + return ClangBackEnd::ProjectPartContainer(projectPart->id(), + Utils::SmallStringVector(arguments), + createCompilerMacros(projectPart->projectMacros), + std::move(includeSearchPaths.system), + std::move(includeSearchPaths.project), + std::move(headerAndSources.headers), + std::move(headerAndSources.sources), + projectPart->language, + projectPart->languageVersion, + static_cast<Utils::LanguageExtension>( + int(projectPart->languageExtensions))); } -std::vector<ClangBackEnd::V2::ProjectPartContainer> ProjectUpdater::toProjectPartContainers( +ClangBackEnd::ProjectPartContainers ProjectUpdater::toProjectPartContainers( std::vector<CppTools::ProjectPart *> projectParts) const { using namespace std::placeholders; - std::vector<ClangBackEnd::V2::ProjectPartContainer> projectPartContainers; + std::vector<ClangBackEnd::ProjectPartContainer> projectPartContainers; projectPartContainers.reserve(projectParts.size()); std::transform(projectParts.begin(), diff --git a/src/plugins/clangpchmanager/projectupdater.h b/src/plugins/clangpchmanager/projectupdater.h index fd4ff95538..896a02def0 100644 --- a/src/plugins/clangpchmanager/projectupdater.h +++ b/src/plugins/clangpchmanager/projectupdater.h @@ -31,6 +31,8 @@ #include <filecontainerv2.h> #include <filepathcachinginterface.h> #include <generatedfiles.h> +#include <includesearchpath.h> +#include <projectpartcontainer.h> #include <projectexplorer/headerpath.h> @@ -46,10 +48,6 @@ class ProjectFile; namespace ClangBackEnd { class ProjectManagementServerInterface; - -namespace V2 { -class ProjectPartContainer; -} } QT_FORWARD_DECLARE_CLASS(QStringList) @@ -64,33 +62,39 @@ class PchManagerClient; class CLANGPCHMANAGER_EXPORT ProjectUpdater { public: + struct SystemAndProjectIncludeSearchPaths + { + ClangBackEnd::IncludeSearchPaths system; + ClangBackEnd::IncludeSearchPaths project; + }; + ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server, ClangBackEnd::FilePathCachingInterface &filePathCache); - void updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts); + void updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts, + Utils::SmallStringVector &&toolChainArguments); void removeProjectParts(const QStringList &projectPartIds); void updateGeneratedFiles(ClangBackEnd::V2::FileContainers &&generatedFiles); void removeGeneratedFiles(ClangBackEnd::FilePaths &&filePaths); -unittest_public: void setExcludedPaths(ClangBackEnd::FilePaths &&excludedPaths); const ClangBackEnd::FilePaths &excludedPaths() const; const ClangBackEnd::GeneratedFiles &generatedFiles() const; HeaderAndSources headerAndSourcesFromProjectPart(CppTools::ProjectPart *projectPart) const; - ClangBackEnd::V2::ProjectPartContainer toProjectPartContainer( + ClangBackEnd::ProjectPartContainer toProjectPartContainer( CppTools::ProjectPart *projectPart) const; - std::vector<ClangBackEnd::V2::ProjectPartContainer> toProjectPartContainers( + ClangBackEnd::ProjectPartContainers toProjectPartContainers( std::vector<CppTools::ProjectPart *> projectParts) const; void addToHeaderAndSources(HeaderAndSources &headerAndSources, const CppTools::ProjectFile &projectFile) const; - static QStringList compilerArguments(CppTools::ProjectPart *projectPart); + static QStringList toolChainArguments(CppTools::ProjectPart *projectPart); static ClangBackEnd::CompilerMacros createCompilerMacros( const ProjectExplorer::Macros &projectMacros); - static Utils::SmallStringVector createIncludeSearchPaths( - const ProjectExplorer::HeaderPaths &projectPartHeaderPaths); + static SystemAndProjectIncludeSearchPaths createIncludeSearchPaths( + const CppTools::ProjectPart &projectPart); static ClangBackEnd::FilePaths createExcludedPaths( const ClangBackEnd::V2::FileContainers &generatedFiles); diff --git a/src/plugins/clangpchmanager/qtcreatorprojectupdater.h b/src/plugins/clangpchmanager/qtcreatorprojectupdater.h index 9be66f1444..9521475692 100644 --- a/src/plugins/clangpchmanager/qtcreatorprojectupdater.h +++ b/src/plugins/clangpchmanager/qtcreatorprojectupdater.h @@ -71,7 +71,8 @@ public: void projectPartsUpdated(ProjectExplorer::Project *project) { - ProjectUpdaterType::updateProjectParts(Internal::createProjectParts(project)); + + ProjectUpdaterType::updateProjectParts(Internal::createProjectParts(project), {}); // TODO add support for toolchainarguments } void projectPartsRemoved(const QStringList &projectPartIds) diff --git a/src/plugins/clangrefactoring/refactoringprojectupdater.cpp b/src/plugins/clangrefactoring/refactoringprojectupdater.cpp index 648e458fd5..99b028e522 100644 --- a/src/plugins/clangrefactoring/refactoringprojectupdater.cpp +++ b/src/plugins/clangrefactoring/refactoringprojectupdater.cpp @@ -35,7 +35,7 @@ void RefactoringProjectUpdater::precompiledHeaderUpdated(const QString &projectP { auto projectPart = m_cppModelManager.projectPartForId(projectPartId); if (projectPart) - updateProjectParts({projectPart.data()}); + updateProjectParts({projectPart.data()}, {}); } void RefactoringProjectUpdater::precompiledHeaderRemoved(const QString &projectPartId) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index c721946593..c3b8f115f2 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -249,6 +249,12 @@ void CompilerOptionsBuilder::addExtraCodeModelFlags() add(m_projectPart.extraCodeModelFlags); } +void CompilerOptionsBuilder::addPicIfCompilerFlagsContainsIt() +{ + if (m_projectPart.compilerFlags.contains("-fPIC")) + add("-fPIC"); +} + void CompilerOptionsBuilder::addCompilerFlags() { add(m_compilerFlags.flags); diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h index 64c07b5fa3..0d0ca84488 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.h +++ b/src/plugins/cpptools/compileroptionsbuilder.h @@ -63,6 +63,7 @@ public: void addTargetTriple(); void addExtraCodeModelFlags(); + void addPicIfCompilerFlagsContainsIt(); void addCompilerFlags(); void insertWrappedQtHeaders(); void addLanguageVersionAndExtensions(); diff --git a/src/plugins/cpptools/cppprojectinfogenerator.cpp b/src/plugins/cpptools/cppprojectinfogenerator.cpp index 29c251bdd4..c177c7a7d9 100644 --- a/src/plugins/cpptools/cppprojectinfogenerator.cpp +++ b/src/plugins/cpptools/cppprojectinfogenerator.cpp @@ -164,6 +164,7 @@ ProjectPart::Ptr ProjectInfoGenerator::createProjectPart( part->extraCodeModelFlags = tcInfo.extraCodeModelFlags; part->compilerFlags = flags.commandLineFlags; part->warningFlags = flags.warningFlags; + part->language = language; part->languageExtensions = flags.languageExtensions; // Toolchain macros and language version diff --git a/src/plugins/cpptools/projectpart.h b/src/plugins/cpptools/projectpart.h index bd5fbee764..e357db3a3d 100644 --- a/src/plugins/cpptools/projectpart.h +++ b/src/plugins/cpptools/projectpart.h @@ -39,6 +39,8 @@ #include <cplusplus/Token.h> +#include <utils/cpplanguage_details.h> + #include <QString> #include <QSharedPointer> @@ -91,6 +93,7 @@ public: QString callGroupId; // Versions, features and extensions + ::Utils::Language language = Utils::Language::Cxx; ::Utils::LanguageVersion languageVersion = ::Utils::LanguageVersion::LatestCxx; ::Utils::LanguageExtensions languageExtensions = ::Utils::LanguageExtension::None; CPlusPlus::LanguageFeatures languageFeatures; diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index db4dc76aaa..4e2b19db8b 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -23,18 +23,24 @@ ** ****************************************************************************/ +#include <builddependenciesprovider.h> +#include <builddependenciesstorage.h> +#include <builddependencycollector.h> #include <clangpathwatcher.h> #include <connectionserver.h> #include <environment.h> #include <generatedfiles.h> +#include <modifiedtimechecker.h> #include <pchcreator.h> #include <pchmanagerserver.h> #include <pchmanagerclientproxy.h> +#include <pchtaskgenerator.h> +#include <pchtaskqueue.h> +#include <pchtasksmerger.h> #include <precompiledheaderstorage.h> #include <processormanager.h> #include <progresscounter.h> #include <projectparts.h> -#include <projectpartqueue.h> #include <filepathcaching.h> #include <refactoringdatabaseinitializer.h> #include <sqlitedatabase.h> @@ -42,12 +48,12 @@ #include <QCommandLineParser> #include <QCoreApplication> +#include <QDateTime> #include <QFileSystemWatcher> #include <QLoggingCategory> #include <QProcess> #include <QTemporaryDir> #include <QTimer> - #include <chrono> #include <thread> @@ -62,6 +68,8 @@ using ClangBackEnd::PchManagerServer; using ClangBackEnd::PrecompiledHeaderStorage; using ClangBackEnd::ProjectParts; using ClangBackEnd::FilePathCache; +using ClangBackEnd::FilePathView; +using ClangBackEnd::TimeStamp; class PchManagerApplication final : public QCoreApplication { @@ -93,11 +101,6 @@ public: return m_pchBuildDirectoryPath; } - QString clangCompilerPath() const override - { - return QString(CLANG_COMPILER_PATH); - } - uint hardwareConcurrency() const override { return std::thread::hardware_concurrency(); @@ -132,13 +135,11 @@ public: PchCreatorManager(const ClangBackEnd::GeneratedFiles &generatedFiles, ClangBackEnd::Environment &environment, Sqlite::Database &database, - PchManagerServer &pchManagerServer, - ClangBackEnd::ClangPathWatcherInterface &fileSystemWatcher) + PchManagerServer &pchManagerServer) : ProcessorManager(generatedFiles), m_environment(environment), m_database(database), - m_pchManagerServer(pchManagerServer), - m_fileSystemWatcher(fileSystemWatcher) + m_pchManagerServer(pchManagerServer) {} protected: @@ -146,25 +147,22 @@ protected: { return std::make_unique<PchCreator>(m_environment, m_database, - *m_pchManagerServer.client(), - m_fileSystemWatcher); + *m_pchManagerServer.client()); } 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<PchCreatorManager, ClangBackEnd::ProjectPartQueue::Task>; + using TaskScheduler = ClangBackEnd::TaskScheduler<PchCreatorManager, ClangBackEnd::PchTaskQueue::Task>; - Data(const QString &databasePath, - const QString &pchsPath) - : database{Utils::PathString{databasePath}, 100000ms}, - environment{pchsPath} + Data(const QString &databasePath, const QString &pchsPath) + : database{Utils::PathString{databasePath}, 100000ms} + , environment{pchsPath} {} Sqlite::Database database; ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database}; @@ -173,12 +171,39 @@ struct Data // because we have a cycle dependency ApplicationEnvironment environment; ProjectParts projectParts; GeneratedFiles generatedFiles; - PchCreatorManager pchCreatorManager{generatedFiles, environment, database, clangPchManagerServer, includeWatcher}; + PchCreatorManager pchCreatorManager{generatedFiles, environment, database, clangPchManagerServer}; PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; - ClangBackEnd::ProgressCounter progressCounter{[&] (int progress, int total) { clangPchManagerServer.setProgress(progress, total); }}; - TaskScheduler taskScheduler{pchCreatorManager, projectPartQueue, progressCounter, std::thread::hardware_concurrency()}; - ClangBackEnd::ProjectPartQueue projectPartQueue{taskScheduler, preCompiledHeaderStorage, database, progressCounter}; - PchManagerServer clangPchManagerServer{includeWatcher, projectPartQueue, projectParts, generatedFiles}; + ClangBackEnd::ProgressCounter progressCounter{ + [&](int progress, int total) { clangPchManagerServer.setProgress(progress, total); }}; + TaskScheduler systemTaskScheduler{pchCreatorManager, + pchTaskQueue, + progressCounter, + std::thread::hardware_concurrency(), + ClangBackEnd::CallDoInMainThreadAfterFinished::No}; + TaskScheduler projectTaskScheduler{pchCreatorManager, + pchTaskQueue, + progressCounter, + std::thread::hardware_concurrency(), + ClangBackEnd::CallDoInMainThreadAfterFinished::Yes}; + ClangBackEnd::PchTaskQueue pchTaskQueue{systemTaskScheduler, + projectTaskScheduler, + progressCounter, + preCompiledHeaderStorage, + database}; + ClangBackEnd::PchTasksMerger pchTaskMerger{pchTaskQueue}; + ClangBackEnd::BuildDependenciesStorage<> buildDependencyStorage{database}; + ClangBackEnd::BuildDependencyCollector buildDependencyCollector{filePathCache}; + std::function<TimeStamp(FilePathView filePath)> getModifiedTime{ + [&](ClangBackEnd::FilePathView path) -> TimeStamp { + return QFileInfo(QString(path)).lastModified().toSecsSinceEpoch(); + }}; + ClangBackEnd::ModifiedTimeChecker modifiedTimeChecker{getModifiedTime, filePathCache}; + ClangBackEnd::BuildDependenciesProvider buildDependencyProvider{buildDependencyStorage, + modifiedTimeChecker, + buildDependencyCollector, + database}; + ClangBackEnd::PchTaskGenerator pchTaskGenerator{buildDependencyProvider, pchTaskMerger}; + PchManagerServer clangPchManagerServer{includeWatcher, pchTaskGenerator, projectParts, generatedFiles}; }; int main(int argc, char *argv[]) diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp index 7f97599fac..d58da0f27c 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp @@ -53,7 +53,7 @@ OutputContainer setUnion(InputContainer1 &&input1, return results; } -BuildDependency BuildDependenciesProvider::create(const V2::ProjectPartContainer &projectPart) +BuildDependency BuildDependenciesProvider::create(const ProjectPartContainer &projectPart) { SourceEntries includes = createSourceEntriesFromStorage(projectPart.sourcePathIds, projectPart.projectPartId); diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h index 386eca587e..4a89ace732 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h @@ -50,7 +50,7 @@ public: , m_transactionBackend(transactionBackend) {} - BuildDependency create(const V2::ProjectPartContainer &projectPart) override; + BuildDependency create(const ProjectPartContainer &projectPart) override; private: BuildDependency createBuildDependencyFromStorage(SourceEntries &&includes) const; diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesproviderinterface.h b/src/tools/clangpchmanagerbackend/source/builddependenciesproviderinterface.h index 0bfaeed06c..7af8c054cc 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesproviderinterface.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesproviderinterface.h @@ -27,14 +27,14 @@ #include "builddependency.h" -#include "projectpartcontainerv2.h" +#include "projectpartcontainer.h" namespace ClangBackEnd { class BuildDependenciesProviderInterface { public: - virtual BuildDependency create(const V2::ProjectPartContainer &projectPart) = 0; + virtual BuildDependency create(const ProjectPartContainer &projectPart) = 0; protected: ~BuildDependenciesProviderInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp b/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp index 4ba3e8c0e6..bfbfbf20cd 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp +++ b/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp @@ -26,6 +26,7 @@ #include "builddependencycollector.h" #include "collectbuilddependencytoolaction.h" +#include "commandlinebuilder.h" #include <utils/smallstring.h> @@ -44,9 +45,12 @@ FilePathIds operator+(const FilePathIds &first, const FilePathIds &second) } } -BuildDependency BuildDependencyCollector::create(const V2::ProjectPartContainer &projectPart) +BuildDependency BuildDependencyCollector::create(const ProjectPartContainer &projectPart) { - addFiles(projectPart.sourcePathIds, projectPart.arguments); + CommandLineBuilder<ProjectPartContainer, Utils::SmallStringVector> builder{ + projectPart, projectPart.toolChainArguments}; + + addFiles(projectPart.sourcePathIds, builder.commandLine); setExcludedFilePaths( m_filePathCache.filePaths(projectPart.headerPathIds + projectPart.sourcePathIds)); diff --git a/src/tools/clangpchmanagerbackend/source/builddependencycollector.h b/src/tools/clangpchmanagerbackend/source/builddependencycollector.h index cab749c316..2ea7fb7c90 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencycollector.h +++ b/src/tools/clangpchmanagerbackend/source/builddependencycollector.h @@ -42,7 +42,7 @@ public: { } - BuildDependency create(const V2::ProjectPartContainer &projectPart) override; + BuildDependency create(const ProjectPartContainer &projectPart) override; void collect(); diff --git a/src/tools/clangpchmanagerbackend/source/builddependencygeneratorinterface.h b/src/tools/clangpchmanagerbackend/source/builddependencygeneratorinterface.h index f6e13f3a1a..0c368e7e25 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencygeneratorinterface.h +++ b/src/tools/clangpchmanagerbackend/source/builddependencygeneratorinterface.h @@ -27,14 +27,14 @@ #include "builddependency.h" -#include "projectpartcontainerv2.h" +#include "projectpartcontainer.h" namespace ClangBackEnd { class BuildDependencyGeneratorInterface { public: - virtual BuildDependency create(const V2::ProjectPartContainer &projectPart) = 0; + virtual BuildDependency create(const ProjectPartContainer &projectPart) = 0; protected: ~BuildDependencyGeneratorInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri index 693e110402..fa8d6e527a 100644 --- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri +++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri @@ -4,7 +4,6 @@ SOURCES += \ $$PWD/builddependenciesprovider.cpp \ $$PWD/pchmanagerserver.cpp \ $$PWD/projectparts.cpp \ - $$PWD/projectpartqueue.cpp \ $$PWD/pchtaskgenerator.cpp \ $$PWD/pchtasksmerger.cpp \ $$PWD/pchtaskqueue.cpp @@ -17,9 +16,7 @@ HEADERS += \ $$PWD/projectparts.h \ $$PWD/pchcreatorinterface.h \ $$PWD/projectpartsinterface.h \ - $$PWD/projectpartqueue.h \ $$PWD/queueinterface.h \ - $$PWD/projectpartqueueinterface.h \ $$PWD/processormanagerinterface.h \ $$PWD/processorinterface.h \ $$PWD/taskscheduler.h \ @@ -40,7 +37,11 @@ HEADERS += \ $$PWD/pchtasksmergerinterface.h \ $$PWD/pchtasksmerger.h \ $$PWD/pchtaskqueueinterface.h \ - $$PWD/pchtaskqueue.h + $$PWD/pchtaskqueue.h \ + $$PWD/generatepchactionfactory.h \ + $$PWD/pchtaskgeneratorinterface.h \ + $$PWD/toolchainargumentscache.h \ + $$PWD/modifiedtimechecker.h !isEmpty(LIBTOOLING_LIBS) { SOURCES += \ diff --git a/src/tools/clangpchmanagerbackend/source/environment.h b/src/tools/clangpchmanagerbackend/source/environment.h index a7deea2b80..7f575fe169 100644 --- a/src/tools/clangpchmanagerbackend/source/environment.h +++ b/src/tools/clangpchmanagerbackend/source/environment.h @@ -37,7 +37,6 @@ public: Environment &operator=(const Environment &) = delete; virtual QString pchBuildDirectory() const = 0; - virtual QString clangCompilerPath() const = 0; virtual uint hardwareConcurrency() const = 0; protected: diff --git a/src/tools/clangpchmanagerbackend/source/generatepchactionfactory.h b/src/tools/clangpchmanagerbackend/source/generatepchactionfactory.h new file mode 100644 index 0000000000..47a64eda92 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/generatepchactionfactory.h @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <clang/Tooling/Tooling.h> + +#include "clang/Frontend/FrontendActions.h" + +namespace ClangBackEnd { +class GeneratePCHActionFactory final : public clang::tooling::FrontendActionFactory +{ +public: + clang::FrontendAction *create() override + { + return new clang::GeneratePCHAction; + } +}; +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h b/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h new file mode 100644 index 0000000000..9e67a27b14 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h @@ -0,0 +1,149 @@ +/**************************************************************************** +** +** 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 "modifiedtimecheckerinterface.h" + +#include <filepathcachinginterface.h> + +#include <algorithm> +#include <iterator> + +namespace ClangBackEnd { + +class ModifiedTimeChecker final : public ModifiedTimeCheckerInterface +{ +public: + using GetModifiedTime = std::function<ClangBackEnd::TimeStamp(ClangBackEnd::FilePathView filePath)>; + ModifiedTimeChecker(GetModifiedTime &getModifiedTime, FilePathCachingInterface &filePathCache) + : m_getModifiedTime(getModifiedTime) + , m_filePathCache(filePathCache) + {} + + bool isUpToDate(const SourceEntries &sourceEntries) const + { + if (sourceEntries.empty()) + return false; + + updateCurrentSourceTimeStamps(sourceEntries); + + return compareEntries(sourceEntries); + } + + void pathsChanged(const FilePathIds &filePathIds) + { + using SourceTimeStampPointers = std::vector<SourceTimeStamp*>; + + class BackInserterIterator : public std::back_insert_iterator<SourceTimeStampPointers> + { + public: + BackInserterIterator(SourceTimeStampPointers &container) + : std::back_insert_iterator<SourceTimeStampPointers>(container) + {} + + BackInserterIterator &operator=(SourceTimeStamp &timeStamp) + { + container->push_back(&timeStamp); + + return *this; + } + + BackInserterIterator &operator*() { return *this; } + }; + + SourceTimeStampPointers timeStampsToUpdate; + timeStampsToUpdate.reserve(filePathIds.size()); + + std::set_intersection(m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end(), + filePathIds.begin(), + filePathIds.end(), + BackInserterIterator(timeStampsToUpdate)); + + for (SourceTimeStamp *sourceTimeStamp : timeStampsToUpdate) { + sourceTimeStamp->lastModified = m_getModifiedTime( + m_filePathCache.filePath(sourceTimeStamp->sourceId)); + } + } + +private: + bool compareEntries(const SourceEntries &sourceEntries) const + { + SourceTimeStamps currentSourceTimeStamp; + currentSourceTimeStamp.reserve(sourceEntries.size()); + std::set_intersection(m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end(), + sourceEntries.begin(), + sourceEntries.end(), + std::back_inserter(currentSourceTimeStamp)); + + return std::equal(currentSourceTimeStamp.begin(), + currentSourceTimeStamp.end(), + sourceEntries.begin(), + sourceEntries.end(), + [](SourceTimeStamp first, SourceTimeStamp second) { + return first.lastModified <= second.lastModified; + }); + } + + void updateCurrentSourceTimeStamps(const SourceEntries &sourceEntries) const + { + SourceTimeStamps sourceTimeStamps = newSourceTimeStamps(sourceEntries); + + for (SourceTimeStamp &newSourceTimeStamp : sourceTimeStamps) { + newSourceTimeStamp.lastModified = m_getModifiedTime( + m_filePathCache.filePath(newSourceTimeStamp.sourceId)); + } + + auto split = sourceTimeStamps.insert(sourceTimeStamps.end(), + m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end()); + std::inplace_merge(sourceTimeStamps.begin(), split, sourceTimeStamps.end()); + + m_currentSourceTimeStamps = sourceTimeStamps; + } + + SourceTimeStamps newSourceTimeStamps(const SourceEntries &sourceEntries) const + { + SourceTimeStamps newTimeStamps; + newTimeStamps.reserve(sourceEntries.size() + m_currentSourceTimeStamps.size()); + + std::set_difference(sourceEntries.begin(), + sourceEntries.end(), + m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end(), + std::back_inserter(newTimeStamps)); + + return newTimeStamps; + } + +private: + mutable SourceTimeStamps m_currentSourceTimeStamps; + GetModifiedTime &m_getModifiedTime; + FilePathCachingInterface &m_filePathCache; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index 79062b5e2d..ea9d7c3e37 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -25,8 +25,10 @@ #include "pchcreator.h" -#include "environment.h" #include "builddependencycollector.h" +#include "commandlinebuilder.h" +#include "environment.h" +#include "generatepchactionfactory.h" #include "pchnotcreatederror.h" #include <clangpathwatcherinterface.h> @@ -45,41 +47,6 @@ namespace ClangBackEnd { namespace { -template <typename Source, - typename Target> -void append(Target &target, const Source &source) -{ - using ValueType = typename Target::value_type; - Source clonedSource = source.clone(); - - target.reserve(target.size() + source.size()); - - for (auto &&entry : clonedSource) - target.push_back(ValueType(std::move(entry))); -} - -void appendFilePathId(ClangBackEnd::FilePaths &target, - const ClangBackEnd::FilePathIds &source, - const ClangBackEnd::FilePathCachingInterface &filePathCache) -{ - for (FilePathId id : source) - target.emplace_back(filePathCache.filePath(id)); -} - -Utils::PathStringVector generatedFilePaths(const V2::FileContainers &generaredFiles) -{ - Utils::PathStringVector generaredFilePaths; - generaredFilePaths.reserve(generaredFiles.size()); - - for (const V2::FileContainer &generatedFile : generaredFiles) - generaredFilePaths.push_back(generatedFile.filePath.path()); - - return generaredFilePaths; -} - -} - -namespace { std::size_t contentSize(const FilePaths &includes) { @@ -106,239 +73,72 @@ Utils::SmallString PchCreator::generatePchIncludeFileContent(const FilePathIds & } -bool PchCreator::generatePch(Utils::SmallStringVector &&compilerArguments) -{ - QProcess process; - - process.setProcessChannelMode(QProcess::ForwardedChannels); - process.setArguments(QStringList(compilerArguments)); - process.setProgram(QString(m_environment.clangCompilerPath())); - - process.start(); - process.waitForFinished(300000); - - return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0; -} - -QStringList PchCreator::convertToQStringList(const Utils::SmallStringVector &compilerArguments) -{ - QStringList qStringList; - - append(qStringList, compilerArguments); - - return qStringList; -} - -namespace { - -void hashProjectPart(QCryptographicHash &hash, const V2::ProjectPartContainer &projectPart) -{ - const auto &projectPartId = projectPart.projectPartId; - hash.addData(projectPartId.data(), int(projectPartId.size())); - - for (const auto &argument : projectPart.arguments) - hash.addData(argument.data(), int(argument.size())); -} -} - -Utils::SmallStringVector PchCreator::generateProjectPartCommandLine( - const V2::ProjectPartContainer &projectPart) const -{ - const Utils::SmallStringVector &arguments = projectPart.arguments; - - Utils::SmallStringVector commandLine; - commandLine.reserve(arguments.size() + 1); - - commandLine.emplace_back(m_environment.clangCompilerPath()); - - append(commandLine , arguments); - - return commandLine; -} - -Utils::SmallString PchCreator::generateProjectPartPchFilePathWithoutExtension( - const V2::ProjectPartContainer &projectPart) const -{ - QByteArray fileName = m_environment.pchBuildDirectory().toUtf8(); - fileName += '/'; - fileName += projectPartHash(projectPart); - - return Utils::SmallString::fromQByteArray(fileName); -} - -Utils::PathStringVector PchCreator::generateProjectPartHeaders( - const V2::ProjectPartContainer &projectPart) const -{ - Utils::PathStringVector headerPaths; - headerPaths.reserve(projectPart.headerPathIds.size() + m_unsavedFiles.size()); - - std::transform(projectPart.headerPathIds.begin(), - projectPart.headerPathIds.end(), - std::back_inserter(headerPaths), - [&] (FilePathId filePathId) { - return m_filePathCache.filePath(filePathId); - }); - - Utils::PathStringVector generatedPath = generatedFilePaths(m_unsavedFiles); - - std::copy(std::make_move_iterator(generatedPath.begin()), - std::make_move_iterator(generatedPath.end()), - std::back_inserter(headerPaths)); - - return headerPaths; -} - -namespace { - -std::size_t sizeOfContent(const ClangBackEnd::FilePaths &paths) -{ - return std::accumulate(paths.begin(), - paths.end(), - std::size_t(0), - [] (std::size_t size, const auto &path) { - const char includeTemplate[] = "#include \"\"\n"; - return size + path.size() + sizeof(includeTemplate); - }); -} - -Utils::SmallString concatContent(const ClangBackEnd::FilePaths &paths, std::size_t size) -{ - Utils::SmallString content; - content.reserve(size); - - for (const ClangBackEnd::FilePath &path : paths) { - content += "#include \""; - content += path; - content += "\"\n"; - }; - - return content; -} - -} - -Utils::SmallString PchCreator::generateProjectPartSourcesContent( - const V2::ProjectPartContainer &projectPart) const -{ - ClangBackEnd::FilePaths paths = generateProjectPartSourcePaths(projectPart); - - return concatContent(paths, sizeOfContent(paths)); -} - -ClangBackEnd::FilePaths PchCreator::generateProjectPartSourcePaths( - const V2::ProjectPartContainer &projectPart) const -{ - ClangBackEnd::FilePaths includeAndSources; - includeAndSources.reserve(projectPart.sourcePathIds.size()); - - appendFilePathId(includeAndSources, projectPart.sourcePathIds, m_filePathCache); - - return includeAndSources; -} - -SourceEntries PchCreator::generateProjectPartPchIncludes( - const V2::ProjectPartContainer &projectPart) const +bool PchCreator::generatePch() { - Utils::SmallString jointedFileContent = generateProjectPartSourcesContent(projectPart); - Utils::SmallString jointedFilePath = generateProjectPartSourceFilePath(projectPart); - auto jointFile = generateFileWithContent(jointedFilePath, jointedFileContent); - Utils::SmallStringVector arguments = generateProjectPartCommandLine(projectPart); - FilePath filePath{Utils::PathString(jointedFilePath)}; - - BuildDependencyCollector collector(m_filePathCache); - - collector.setExcludedFilePaths(generateProjectPartSourcePaths(projectPart)); + clang::tooling::ClangTool tool = m_clangTool.createOutputTool(); - collector.addFile(filePath, projectPart.sourcePathIds, arguments); + auto action = std::make_unique<GeneratePCHActionFactory>(); - collector.addUnsavedFiles(m_unsavedFiles); - - collector.collect(); - - jointFile->remove(); - - return collector.includeIds(); + return tool.run(action.get()) != 1; } -Utils::SmallString PchCreator::generateProjectPathPchHeaderFilePath( - const V2::ProjectPartContainer &projectPart) const +FilePath PchCreator::generatePchHeaderFilePath() const { - return Utils::SmallString{generateProjectPartPchFilePathWithoutExtension(projectPart), ".h"}; -} + std::uniform_int_distribution<std::mt19937_64::result_type> distribution; -Utils::SmallString PchCreator::generateProjectPartPchFilePath( - const V2::ProjectPartContainer &projectPart) const -{ - return Utils::SmallString{generateProjectPartPchFilePathWithoutExtension(projectPart), ".pch"}; + return FilePathView{Utils::PathString{Utils::SmallString(m_environment.pchBuildDirectory()), + "/", + std::to_string(distribution(randomNumberGenator)), + ".h"}}; } -Utils::SmallString PchCreator::generateProjectPartSourceFilePath(const V2::ProjectPartContainer &projectPart) const +FilePath PchCreator::generatePchFilePath() const { - return Utils::SmallString{generateProjectPartPchFilePathWithoutExtension(projectPart), ".cpp"}; -} + std::uniform_int_distribution<std::uint_fast64_t> distribution( + 1, std::numeric_limits<std::uint_fast64_t>::max()); -Utils::SmallStringVector PchCreator::generateProjectPartPchCompilerArguments( - const V2::ProjectPartContainer &projectPart) 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(generateProjectPartPchFilePath(projectPart)); - arguments.emplace_back(generateProjectPathPchHeaderFilePath(projectPart)); - - return arguments; + return FilePathView{Utils::PathString{Utils::SmallString(m_environment.pchBuildDirectory()), + "/", + std::to_string(distribution(randomNumberGenator)), + ".pch"}}; } -Utils::SmallStringVector PchCreator::generateProjectPartClangCompilerArguments( - const V2::ProjectPartContainer &projectPart) const +std::vector<std::string> PchCreator::generateClangCompilerArguments( + PchTask &&pchTask, + FilePathView sourceFilePath, + FilePathView pchOutputPath) { - Utils::SmallStringVector compilerArguments = projectPart.arguments.clone(); - const auto pchArguments = generateProjectPartPchCompilerArguments(projectPart); - - append(compilerArguments, pchArguments); + CommandLineBuilder<PchTask> builder{pchTask, + pchTask.toolChainArguments, + sourceFilePath, + pchOutputPath, + pchTask.systemPchPath}; - return compilerArguments; + return builder.commandLine; } -IdPaths PchCreator::generateProjectPartPch(const V2::ProjectPartContainer &projectPart) +void PchCreator::generatePch(PchTask &&pchTask) { long long lastModified = QDateTime::currentSecsSinceEpoch(); - auto includes = generateProjectPartPchIncludes(projectPart); - auto content = generatePchIncludeFileContent(topIncludeIds(includes)); - auto pchIncludeFilePath = generateProjectPathPchHeaderFilePath(projectPart); - auto pchFilePath = generateProjectPartPchFilePath(projectPart); - generateFileWithContent(pchIncludeFilePath, content); + auto content = generatePchIncludeFileContent(pchTask.includes); + auto pchSourceFilePath = generatePchHeaderFilePath(); + auto pchOutputPath = generatePchFilePath(); + generateFileWithContent(pchSourceFilePath, content); - bool success = generatePch(generateProjectPartClangCompilerArguments(projectPart)); + m_clangTool.addFile( + pchSourceFilePath.directory(), + pchSourceFilePath.name(), + "", + generateClangCompilerArguments(std::move(pchTask), pchSourceFilePath, pchOutputPath)); - m_projectPartPch.projectPartId = projectPart.projectPartId; + bool success = generatePch(); + + m_projectPartPch.projectPartId = pchTask.projectPartId(); if (success) { - m_projectPartPch.pchPath = std::move(pchFilePath); + m_projectPartPch.pchPath = std::move(pchOutputPath); m_projectPartPch.lastModified = lastModified; } - - return {projectPart.projectPartId.clone(), allIncludeIds(includes)}; -} - -void PchCreator::generatePchDeprecated(const V2::ProjectPartContainer &projectPart) -{ - m_projectIncludeIds = generateProjectPartPch(projectPart); -} - -void PchCreator::generatePch(const PchTask &pchTask) -{ - -} - -IdPaths PchCreator::takeProjectIncludes() -{ - return std::move(m_projectIncludeIds); } const ProjectPartPch &PchCreator::projectPartPch() @@ -363,19 +163,12 @@ bool PchCreator::isUsed() const void PchCreator::clear() { - m_projectPartPch = ProjectPartPch{}; - m_projectIncludeIds = IdPaths{}; + m_projectPartPch = {}; } 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() @@ -383,9 +176,8 @@ const FilePathCaching &PchCreator::filePathCache() return m_filePathCache; } -std::unique_ptr<QFile> PchCreator::generateFileWithContent( - const Utils::SmallString &filePath, - const Utils::SmallString &content) +std::unique_ptr<QFile> PchCreator::generateFileWithContent(const Utils::SmallString &filePath, + const Utils::SmallString &content) { std::unique_ptr<QFile> precompiledIncludeFile(new QFile(QString(filePath))); @@ -397,41 +189,4 @@ std::unique_ptr<QFile> PchCreator::generateFileWithContent( return precompiledIncludeFile; } -FilePathIds PchCreator::topIncludeIds(const SourceEntries &includes) -{ - FilePathIds topIncludes; - topIncludes.reserve(includes.size()); - - for (SourceEntry include : includes) { - if (include.sourceType == SourceType::TopProjectInclude) - topIncludes.push_back(include.sourceId); - } - - return topIncludes; -} - -FilePathIds PchCreator::allIncludeIds(const SourceEntries &includes) -{ - FilePathIds allIncludes; - allIncludes.reserve(includes.size()); - - std::transform(includes.begin(), - includes.end(), - std::back_inserter(allIncludes), - [](auto &&entry) { return entry.sourceId; }); - - return allIncludes; -} - -QByteArray PchCreator::projectPartHash(const V2::ProjectPartContainer &projectPart) -{ - QCryptographicHash hash(QCryptographicHash::Sha1); - - hashProjectPart(hash, projectPart); - - auto result = hash.result(); - - return result.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); -} - } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.h b/src/tools/clangpchmanagerbackend/source/pchcreator.h index 34170e2bb5..ce1b7ab1eb 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.h @@ -29,12 +29,14 @@ #include "idpaths.h" #include "sourceentry.h" +#include "clangtool.h" #include <filepathcaching.h> #include <projectpartpch.h> -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> #include <vector> +#include <random> QT_FORWARD_DECLARE_CLASS(QFile) QT_FORWARD_DECLARE_CLASS(QCryptographicHash) @@ -60,18 +62,13 @@ class PchCreator final : public PchCreatorInterface public: PchCreator(Environment &environment, Sqlite::Database &database, - PchManagerClientInterface &pchManagerClient, - ClangPathWatcherInterface &fileSystemWatcher) - : m_filePathCache(database), - m_environment(environment), - m_pchManagerClient(pchManagerClient), - m_fileSystemWatcher(fileSystemWatcher) - { - } - - void generatePchDeprecated(const V2::ProjectPartContainer &projectsPart) override; - void generatePch(const PchTask &pchTask) override; - IdPaths takeProjectIncludes() override; + PchManagerClientInterface &pchManagerClient) + : m_filePathCache(database) + , m_environment(environment) + , m_pchManagerClient(pchManagerClient) + {} + + void generatePch(PchTask &&pchTask) override; const ProjectPartPch &projectPartPch() override; void setUnsavedFiles(const V2::FileContainers &fileContainers) override; void setIsUsed(bool isUsed) override; @@ -79,56 +76,27 @@ public: void clear() override; void doInMainThreadAfterFinished() override; - const IdPaths &projectIncludes() const; const FilePathCaching &filePathCache(); Utils::SmallString generatePchIncludeFileContent(const FilePathIds &includeIds) const; - bool generatePch(Utils::SmallStringVector &&commandLineArguments); - - static QStringList convertToQStringList(const Utils::SmallStringVector &convertToQStringList); - - Utils::SmallStringVector generateProjectPartCommandLine( - const V2::ProjectPartContainer &projectPart) const; - Utils::SmallString generateProjectPartPchFilePathWithoutExtension( - const V2::ProjectPartContainer &projectPart) const; - Utils::PathStringVector generateProjectPartHeaders( - const V2::ProjectPartContainer &projectPart) const; - Utils::SmallString generateProjectPartSourcesContent( - const V2::ProjectPartContainer &projectPart) const; - ClangBackEnd::FilePaths generateProjectPartSourcePaths( - const V2::ProjectPartContainer &projectPart) const; - SourceEntries generateProjectPartPchIncludes( - const V2::ProjectPartContainer &projectPart) const; - Utils::SmallString generateProjectPathPchHeaderFilePath( - const V2::ProjectPartContainer &projectPart) const; - Utils::SmallString generateProjectPartPchFilePath( - const V2::ProjectPartContainer &projectPart) const; - Utils::SmallString generateProjectPartSourceFilePath( - const V2::ProjectPartContainer &projectPart) const; - Utils::SmallStringVector generateProjectPartPchCompilerArguments( - const V2::ProjectPartContainer &projectPart) const; - Utils::SmallStringVector generateProjectPartClangCompilerArguments( - const V2::ProjectPartContainer &projectPart) const; - IdPaths generateProjectPartPch( - const V2::ProjectPartContainer &projectPart); - static std::unique_ptr<QFile> generateFileWithContent( - const Utils::SmallString &filePath, - const Utils::SmallString &content); - - static FilePathIds topIncludeIds(const SourceEntries &includes); - static FilePathIds allIncludeIds(const SourceEntries &includes); + bool generatePch(); -private: - static QByteArray projectPartHash(const V2::ProjectPartContainer &projectPart); + FilePath generatePchHeaderFilePath() const; + FilePath generatePchFilePath() const; + static std::vector<std::string> generateClangCompilerArguments(PchTask &&pchTask, + FilePathView includePchHeaderPath, + FilePathView pchPath); + static std::unique_ptr<QFile> generateFileWithContent(const Utils::SmallString &filePath, + const Utils::SmallString &content); private: + mutable std::mt19937_64 randomNumberGenator{std::random_device{}()}; + ClangTool m_clangTool; ProjectPartPch m_projectPartPch; - IdPaths m_projectIncludeIds; FilePathCaching m_filePathCache; V2::FileContainers m_unsavedFiles; Environment &m_environment; PchManagerClientInterface &m_pchManagerClient; - ClangPathWatcherInterface &m_fileSystemWatcher; bool m_isUsed = false; }; diff --git a/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h b/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h index caa2d67649..dd16e78f59 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h @@ -31,7 +31,7 @@ #include "processorinterface.h" #include <filecontainerv2.h> -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> namespace ClangBackEnd { @@ -42,9 +42,7 @@ public: PchCreatorInterface(const PchCreatorInterface &) = delete; PchCreatorInterface &operator=(const PchCreatorInterface &) = delete; - virtual void generatePchDeprecated(const V2::ProjectPartContainer &projectsPart) = 0; - virtual void generatePch(const PchTask &pchTask) = 0; - virtual IdPaths takeProjectIncludes() = 0; + virtual void generatePch(PchTask &&pchTask) = 0; virtual const ProjectPartPch &projectPartPch() = 0; protected: diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp index 0bc5c10879..2f53560632 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp @@ -28,7 +28,7 @@ #include <pchmanagerclientinterface.h> #include <precompiledheadersupdatedmessage.h> #include <progressmessage.h> -#include <projectpartqueue.h> +#include <pchtaskgeneratorinterface.h> #include <removegeneratedfilesmessage.h> #include <removeprojectpartsmessage.h> #include <updategeneratedfilesmessage.h> @@ -41,11 +41,11 @@ namespace ClangBackEnd { PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, - ProjectPartQueueInterface &projectPartQueue, + PchTaskGeneratorInterface &pchTaskGenerator, ProjectPartsInterface &projectParts, GeneratedFilesInterface &generatedFiles) : m_fileSystemWatcher(fileSystemWatcher), - m_projectPartQueue(projectPartQueue), + m_pchTaskGenerator(pchTaskGenerator), m_projectParts(projectParts), m_generatedFiles(generatedFiles) { @@ -55,12 +55,14 @@ PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, void PchManagerServer::end() { QCoreApplication::exit(); - } void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message) { - m_projectPartQueue.addProjectParts(m_projectParts.update(message.takeProjectsParts())); + m_toolChainsArgumentsCache.update(message.projectsParts, message.toolChainArguments); + + m_pchTaskGenerator.addProjectParts( + m_projectParts.update(message.takeProjectsParts()), std::move(message.toolChainArguments)); } void PchManagerServer::removeProjectParts(RemoveProjectPartsMessage &&message) @@ -69,7 +71,9 @@ void PchManagerServer::removeProjectParts(RemoveProjectPartsMessage &&message) m_projectParts.remove(message.projectsPartIds); - m_projectPartQueue.removeProjectParts(message.projectsPartIds); + m_pchTaskGenerator.removeProjectParts(message.projectsPartIds); + + m_toolChainsArgumentsCache.remove(message.projectsPartIds); } void PchManagerServer::updateGeneratedFiles(UpdateGeneratedFilesMessage &&message) @@ -84,7 +88,12 @@ void PchManagerServer::removeGeneratedFiles(RemoveGeneratedFilesMessage &&messag void PchManagerServer::pathsWithIdsChanged(const Utils::SmallStringVector &ids) { - m_projectPartQueue.addProjectParts(m_projectParts.projects(ids)); + ArgumentsEntries entries = m_toolChainsArgumentsCache.arguments(ids); + + for (ArgumentsEntry &entry : entries) { + m_pchTaskGenerator.addProjectParts( + m_projectParts.projects(entry.ids), std::move(entry.arguments)); + } } void PchManagerServer::pathsChanged(const FilePathIds &/*filePathIds*/) diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h index b3ff135f52..0c4bd0cc66 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h @@ -30,6 +30,7 @@ #include "pchcreatorinterface.h" #include "pchmanagerserverinterface.h" #include "projectpartsinterface.h" +#include "toolchainargumentscache.h" #include <generatedfilesinterface.h> #include <ipcclientprovider.h> @@ -37,7 +38,7 @@ namespace ClangBackEnd { class SourceRangesAndDiagnosticsForQueryMessage; -class ProjectPartQueueInterface; +class PchTaskGeneratorInterface; class PchManagerServer : public PchManagerServerInterface, public ClangPathWatcherNotifier, @@ -46,7 +47,7 @@ class PchManagerServer : public PchManagerServerInterface, { public: PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, - ProjectPartQueueInterface &projectPartQueue, + PchTaskGeneratorInterface &pchTaskGenerator, ProjectPartsInterface &projectParts, GeneratedFilesInterface &generatedFiles); @@ -63,9 +64,10 @@ public: private: ClangPathWatcherInterface &m_fileSystemWatcher; - ProjectPartQueueInterface &m_projectPartQueue; + PchTaskGeneratorInterface &m_pchTaskGenerator; ProjectPartsInterface &m_projectParts; GeneratedFilesInterface &m_generatedFiles; + ToolChainsArgumentsCache m_toolChainsArgumentsCache; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchtask.h b/src/tools/clangpchmanagerbackend/source/pchtask.h index a78b199215..071cbfcb6b 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtask.h +++ b/src/tools/clangpchmanagerbackend/source/pchtask.h @@ -28,8 +28,11 @@ #include "builddependency.h" #include <compilermacro.h> +#include <filepath.h> +#include <includesearchpath.h> #include <utils/smallstringvector.h> +#include <utils/cpplanguage_details.h> namespace ClangBackEnd { @@ -39,21 +42,45 @@ public: PchTask(Utils::SmallString &&projectPartId, FilePathIds &&includes, CompilerMacros &&compilerMacros, - UsedMacros &&usedMacros) + UsedMacros &&usedMacros, + Utils::SmallStringVector toolChainArguments, + IncludeSearchPaths systemIncludeSearchPaths, + IncludeSearchPaths projectIncludeSearchPaths, + Utils::Language language = Utils::Language::Cxx, + Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98, + Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None) : projectPartIds({projectPartId}) , includes(includes) , compilerMacros(compilerMacros) , usedMacros(usedMacros) + , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) + , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) + , toolChainArguments(std::move(toolChainArguments)) + , language(language) + , languageVersion(languageVersion) + , languageExtension(languageExtension) {} PchTask(Utils::SmallStringVector &&projectPartIds, FilePathIds &&includes, CompilerMacros &&compilerMacros, - UsedMacros &&usedMacros) + UsedMacros &&usedMacros, + Utils::SmallStringVector toolChainArguments, + IncludeSearchPaths systemIncludeSearchPaths, + IncludeSearchPaths projectIncludeSearchPaths, + Utils::Language language = Utils::Language::Cxx, + Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98, + Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None) : projectPartIds(std::move(projectPartIds)) , includes(includes) , compilerMacros(compilerMacros) , usedMacros(usedMacros) + , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) + , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) + , toolChainArguments(std::move(toolChainArguments)) + , language(language) + , languageVersion(languageVersion) + , languageExtension(languageExtension) {} friend bool operator==(const PchTask &first, const PchTask &second) @@ -61,17 +88,29 @@ public: return first.systemPchPath == second.systemPchPath && first.projectPartIds == second.projectPartIds && first.includes == second.includes && first.compilerMacros == second.compilerMacros - && first.usedMacros == second.usedMacros; + && first.usedMacros == second.usedMacros + && first.systemIncludeSearchPaths == second.systemIncludeSearchPaths + && first.projectIncludeSearchPaths == second.projectIncludeSearchPaths + && first.toolChainArguments == second.toolChainArguments + && first.language == second.language + && first.languageVersion == second.languageVersion + && first.languageExtension == second.languageExtension; } Utils::SmallStringView projectPartId() const { return projectPartIds.front(); } public: - Utils::PathString systemPchPath; + FilePath systemPchPath; Utils::SmallStringVector projectPartIds; FilePathIds includes; CompilerMacros compilerMacros; UsedMacros usedMacros; + IncludeSearchPaths systemIncludeSearchPaths; + IncludeSearchPaths projectIncludeSearchPaths; + Utils::SmallStringVector toolChainArguments; + Utils::Language language = Utils::Language::Cxx; + Utils::LanguageVersion languageVersion = Utils::LanguageVersion::CXX98; + Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None; }; class PchTaskSet diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp index 37311aa238..8159dbeb12 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp @@ -34,7 +34,8 @@ namespace ClangBackEnd { -void PchTaskGenerator::create(V2::ProjectPartContainers &&projectParts) +void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, + Utils::SmallStringVector &&toolChainArguments) { PchTaskSets pchTaskSets; pchTaskSets.reserve(projectParts.size()); @@ -46,18 +47,33 @@ void PchTaskGenerator::create(V2::ProjectPartContainers &&projectParts) filter.filter(projectPart.compilerMacros); pchTaskSets.emplace_back(PchTask{projectPart.projectPartId.clone(), - std::move(filter.systemIncludes), + std::move(filter.topSystemIncludes), std::move(filter.systemCompilerMacros), - std::move(filter.systemUsedMacros) - - }, + std::move(filter.systemUsedMacros), + projectPart.toolChainArguments, + projectPart.systemIncludeSearchPaths, + projectPart.projectIncludeSearchPaths, + projectPart.language, + projectPart.languageVersion, + projectPart.languageExtension}, PchTask{std::move(projectPart.projectPartId), - std::move(filter.projectIncludes), + std::move(filter.topProjectIncludes), std::move(filter.projectCompilerMacros), - std::move(filter.projectUsedMacros)}); + std::move(filter.projectUsedMacros), + projectPart.toolChainArguments, + projectPart.systemIncludeSearchPaths, + projectPart.projectIncludeSearchPaths, + projectPart.language, + projectPart.languageVersion, + projectPart.languageExtension}); } - m_pchTasksMergerInterface.mergeTasks(std::move(pchTaskSets)); + m_pchTasksMergerInterface.mergeTasks(std::move(pchTaskSets), std::move(toolChainArguments)); +} + +void PchTaskGenerator::removeProjectParts(const Utils::SmallStringVector &projectsPartIds) +{ + m_pchTasksMergerInterface.removePchTasks(projectsPartIds); } } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.h b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.h index d7a7937d80..b5669b7b3f 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.h +++ b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.h @@ -26,8 +26,9 @@ #pragma once #include "pchtask.h" +#include "pchtaskgeneratorinterface.h" -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> namespace ClangBackEnd { @@ -35,7 +36,7 @@ class PchTasksMergerInterface; class BuildDependenciesProviderInterface; -class PchTaskGenerator +class PchTaskGenerator : public PchTaskGeneratorInterface { public: PchTaskGenerator(BuildDependenciesProviderInterface &buildDependenciesProvider, @@ -44,7 +45,9 @@ public: , m_pchTasksMergerInterface(pchTasksMergerInterface) {} - void create(V2::ProjectPartContainers &&projectParts); + void addProjectParts(ProjectPartContainers &&projectParts, + Utils::SmallStringVector &&toolChainArguments); + void removeProjectParts(const Utils::SmallStringVector &projectsPartIds); private: BuildDependenciesProviderInterface &m_buildDependenciesProvider; diff --git a/src/tools/clangpchmanagerbackend/source/projectpartqueueinterface.h b/src/tools/clangpchmanagerbackend/source/pchtaskgeneratorinterface.h index 0b705fe312..4546284265 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartqueueinterface.h +++ b/src/tools/clangpchmanagerbackend/source/pchtaskgeneratorinterface.h @@ -25,19 +25,20 @@ #pragma once -#include "queueinterface.h" - -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> namespace ClangBackEnd { -class ProjectPartQueueInterface : public QueueInterface +class PchTaskGeneratorInterface { public: - virtual void addProjectParts(V2::ProjectPartContainers &&projectParts) = 0; + virtual void addProjectParts(ProjectPartContainers &&projectParts, + Utils::SmallStringVector &&toolChainArguments) + = 0; virtual void removeProjectParts(const Utils::SmallStringVector &projectsPartIds) = 0; protected: - ~ProjectPartQueueInterface() = default; + ~PchTaskGeneratorInterface() = default; }; + } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskqueue.cpp b/src/tools/clangpchmanagerbackend/source/pchtaskqueue.cpp index 6b82290ef1..6c1a09fd3e 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtaskqueue.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtaskqueue.cpp @@ -52,8 +52,6 @@ void PchTaskQueue::addPchTasks(PchTasks &&newPchTasks, PchTasks &destination) destination = std::move(mergedPchTasks); m_progressCounter.addTotal(int(destination.size() - oldSize)); - - processEntries(); } void PchTaskQueue::removePchTasksByProjectPartId(const Utils::SmallStringVector &projectsPartIds, @@ -143,22 +141,17 @@ std::vector<PchTaskQueue::Task> PchTaskQueue::createProjectTasks(PchTasks &&pchT auto convert = [this](auto &&pchTask) { return [pchTask = std::move(pchTask), this](PchCreatorInterface &pchCreator) mutable { - Sqlite::DeferredTransaction readTransaction(m_transactionsInterface); + const auto projectPartId = pchTask.projectPartId(); pchTask.systemPchPath = m_precompiledHeaderStorage.fetchSystemPrecompiledHeaderPath( - pchTask.projectPartId()); - readTransaction.commit(); - pchCreator.generatePch(pchTask); + projectPartId); + pchCreator.generatePch(std::move(pchTask)); const auto &projectPartPch = pchCreator.projectPartPch(); - Sqlite::ImmediateTransaction writeTransaction(m_transactionsInterface); if (projectPartPch.pchPath.empty()) { - m_precompiledHeaderStorage.deleteProjectPrecompiledHeader(pchTask.projectPartId()); + m_precompiledHeaderStorage.deleteProjectPrecompiledHeader(projectPartId); } else { - m_precompiledHeaderStorage - .insertProjectPrecompiledHeader(pchTask.projectPartId(), - projectPartPch.pchPath, - projectPartPch.lastModified); + m_precompiledHeaderStorage.insertProjectPrecompiledHeader( + projectPartId, projectPartPch.pchPath, projectPartPch.lastModified); } - writeTransaction.commit(); }; }; @@ -176,21 +169,17 @@ std::vector<PchTaskQueue::Task> PchTaskQueue::createSystemTasks(PchTasks &&pchTa tasks.reserve(pchTasks.size()); auto convert = [this](auto &&pchTask) { - return [pchTask = std::move(pchTask), this](PchCreatorInterface &pchCreator) { - pchCreator.generatePch(pchTask); + return [pchTask = std::move(pchTask), this](PchCreatorInterface &pchCreator) mutable { + const auto projectPartIds = pchTask.projectPartIds; + pchCreator.generatePch(std::move(pchTask)); const auto &projectPartPch = pchCreator.projectPartPch(); - Sqlite::ImmediateTransaction transaction(m_transactionsInterface); - for (Utils::SmallStringView projectPartId : pchTask.projectPartIds) { - if (projectPartPch.pchPath.empty()) { - m_precompiledHeaderStorage.deleteSystemPrecompiledHeader(projectPartId); - } else { - m_precompiledHeaderStorage - .insertSystemPrecompiledHeader(projectPartId, - projectPartPch.pchPath, - projectPartPch.lastModified); - } + if (projectPartPch.pchPath.empty()) { + m_precompiledHeaderStorage.deleteSystemPrecompiledHeaders(projectPartIds); + } else { + m_precompiledHeaderStorage.insertSystemPrecompiledHeaders(projectPartIds, + projectPartPch.pchPath, + projectPartPch.lastModified); } - transaction.commit(); }; }; diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp index a241c60764..9ace04e09d 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp @@ -29,7 +29,8 @@ namespace ClangBackEnd { -void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets) +void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets, + Utils::SmallStringVector &&/*toolChainArguments*/) { PchTasks systemTasks; systemTasks.reserve(taskSets.size()); @@ -46,4 +47,9 @@ void PchTasksMerger::mergeTasks(PchTaskSets &&taskSets) m_pchTaskQueue.processEntries(); } +void PchTasksMerger::removePchTasks(const Utils::SmallStringVector &projectPartIds) +{ + m_pchTaskQueue.removePchTasks(projectPartIds); +} + } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h index 97bed64e99..9c777b8a7c 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h +++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.h @@ -39,7 +39,8 @@ public: : m_pchTaskQueue(pchTaskQueue) {} - void mergeTasks(PchTaskSets &&taskSets) override; + void mergeTasks(PchTaskSets &&taskSets, Utils::SmallStringVector &&toolChainArguments) override; + void removePchTasks(const Utils::SmallStringVector &projectPartIds) override; private: PchTaskQueueInterface &m_pchTaskQueue; diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmergerinterface.h b/src/tools/clangpchmanagerbackend/source/pchtasksmergerinterface.h index 4fe96581bc..a691766b49 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtasksmergerinterface.h +++ b/src/tools/clangpchmanagerbackend/source/pchtasksmergerinterface.h @@ -31,7 +31,8 @@ namespace ClangBackEnd { class PchTasksMergerInterface { public: - virtual void mergeTasks(PchTaskSets &&taskSets) = 0; + virtual void mergeTasks(PchTaskSets &&taskSets, Utils::SmallStringVector &&toolChainArguments) = 0; + virtual void removePchTasks(const Utils::SmallStringVector &projectPartIds) = 0; protected: ~PchTasksMergerInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h index 67ee9b4fe6..022f5d926b 100644 --- a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h @@ -48,8 +48,8 @@ public: } void insertProjectPrecompiledHeader(Utils::SmallStringView projectPartName, - Utils::SmallStringView pchPath, - long long pchBuildTime) override + Utils::SmallStringView pchPath, + long long pchBuildTime) override { try { Sqlite::ImmediateTransaction transaction{m_database}; @@ -76,42 +76,44 @@ public: } } - void insertSystemPrecompiledHeader(Utils::SmallStringView projectPartName, - Utils::SmallStringView pchPath, - long long pchBuildTime) override + void insertSystemPrecompiledHeaders(const Utils::SmallStringVector &projectPartNames, + Utils::SmallStringView pchPath, + long long pchBuildTime) override { try { Sqlite::ImmediateTransaction transaction{m_database}; - m_insertProjectPartStatement.write(projectPartName); - m_insertSystemPrecompiledHeaderStatement.write(projectPartName, pchPath, pchBuildTime); - + for (Utils::SmallStringView projectPartName : projectPartNames) { + m_insertProjectPartStatement.write(projectPartName); + m_insertSystemPrecompiledHeaderStatement.write(projectPartName, pchPath, pchBuildTime); + } transaction.commit(); } catch (const Sqlite::StatementIsBusy) { - insertSystemPrecompiledHeader(projectPartName, pchPath, pchBuildTime); + insertSystemPrecompiledHeaders(projectPartNames, pchPath, pchBuildTime); } } - void deleteSystemPrecompiledHeader(Utils::SmallStringView projectPartName) override + void deleteSystemPrecompiledHeaders(const Utils::SmallStringVector &projectPartNames) override { try { Sqlite::ImmediateTransaction transaction{m_database}; - m_deleteSystemPrecompiledHeaderStatement.write(projectPartName); + for (Utils::SmallStringView projectPartName : projectPartNames) + m_deleteSystemPrecompiledHeaderStatement.write(projectPartName); transaction.commit(); } catch (const Sqlite::StatementIsBusy) { - deleteSystemPrecompiledHeader(projectPartName); + deleteSystemPrecompiledHeaders(projectPartNames); } } - Utils::PathString fetchSystemPrecompiledHeaderPath(Utils::SmallStringView projectPartName) override + FilePath fetchSystemPrecompiledHeaderPath(Utils::SmallStringView projectPartName) override { try { Sqlite::DeferredTransaction transaction{m_database}; - auto value = m_fetchSystemPrecompiledHeaderPathStatement - .template value<Utils::PathString>(projectPartName); + auto value = m_fetchSystemPrecompiledHeaderPathStatement.template value<FilePath>( + projectPartName); if (value) return value.value(); @@ -121,7 +123,7 @@ public: return fetchSystemPrecompiledHeaderPath(projectPartName); } - return Utils::SmallStringView(""); + return FilePath(""); } public: diff --git a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h index 2ade4e885a..2a7e11604b 100644 --- a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h @@ -25,7 +25,9 @@ #pragma once -#include <utils/smallstring.h> +#include <filepath.h> + +#include <utils/smallstringvector.h> namespace ClangBackEnd { @@ -42,13 +44,12 @@ public: long long pchBuildTime) = 0; virtual void deleteProjectPrecompiledHeader(Utils::SmallStringView projectPartName) = 0; - virtual void insertSystemPrecompiledHeader(Utils::SmallStringView projectPartName, - Utils::SmallStringView pchPath, - long long pchBuildTime) + virtual void insertSystemPrecompiledHeaders(const Utils::SmallStringVector &projectPartNames, + Utils::SmallStringView pchPath, + long long pchBuildTime) = 0; - virtual void deleteSystemPrecompiledHeader(Utils::SmallStringView projectPartName) = 0; - virtual Utils::PathString fetchSystemPrecompiledHeaderPath( - Utils::SmallStringView projectPartName) = 0; + virtual void deleteSystemPrecompiledHeaders(const Utils::SmallStringVector &projectPartNames) = 0; + virtual FilePath fetchSystemPrecompiledHeaderPath(Utils::SmallStringView projectPartName) = 0; protected: ~PrecompiledHeaderStorageInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/projectpartqueue.cpp b/src/tools/clangpchmanagerbackend/source/projectpartqueue.cpp deleted file mode 100644 index 48f133f7d7..0000000000 --- a/src/tools/clangpchmanagerbackend/source/projectpartqueue.cpp +++ /dev/null @@ -1,137 +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 "projectpartqueue.h" - -#include <pchcreatorinterface.h> -#include <precompiledheaderstorageinterface.h> -#include <progresscounter.h> -#include <sqlitetransaction.h> - -namespace ClangBackEnd { - -void ProjectPartQueue::addProjectParts(V2::ProjectPartContainers &&projectParts) -{ - auto compare = [](const V2::ProjectPartContainer &first, const V2::ProjectPartContainer &second) { - return first.projectPartId < second.projectPartId; - }; - - const std::size_t oldSize = m_projectParts.size(); - - 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); - - m_progressCounter.addTotal(int(m_projectParts.size() - oldSize)); - - processEntries(); -} - -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) -{ - const std::size_t oldSize = m_projectParts.size(); - - 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); - - m_progressCounter.removeTotal(int(oldSize - m_projectParts.size())); -} - -void ProjectPartQueue::processEntries() -{ - uint taskCount = m_taskScheduler.slotUsage().free; - - auto newEnd = std::prev(m_projectParts.end(), std::min<int>(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::Task> ProjectPartQueue::createPchTasks( - V2::ProjectPartContainers &&projectParts) const -{ - std::vector<Task> tasks; - tasks.reserve(projectParts.size()); - - auto convert = [this] (auto &&projectPart) { - return [projectPart=std::move(projectPart), this] (PchCreatorInterface &pchCreator) { - pchCreator.generatePchDeprecated(projectPart); - const auto &projectPartPch = pchCreator.projectPartPch(); - Sqlite::ImmediateTransaction transaction(m_transactionsInterface); - if (projectPartPch.pchPath.empty()) { - m_precompiledHeaderStorage.deleteProjectPrecompiledHeader(projectPartPch.projectPartId); - } else { - m_precompiledHeaderStorage.insertProjectPrecompiledHeader(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/clangpchmanagerbackend/source/projectpartqueue.h b/src/tools/clangpchmanagerbackend/source/projectpartqueue.h deleted file mode 100644 index 9365d7e5cc..0000000000 --- a/src/tools/clangpchmanagerbackend/source/projectpartqueue.h +++ /dev/null @@ -1,74 +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 "projectpartqueueinterface.h" -#include "taskschedulerinterface.h" - -namespace Sqlite { -class TransactionInterface; -} - -namespace ClangBackEnd { - -class PrecompiledHeaderStorageInterface; -class ProgressCounter; -class PchTaskSchedulerInterface; -class PchCreatorInterface; - -class ProjectPartQueue final : public ProjectPartQueueInterface -{ -public: - using Task = std::function<void (PchCreatorInterface&)>; - - ProjectPartQueue(TaskSchedulerInterface<Task> &taskScheduler, - PrecompiledHeaderStorageInterface &precompiledHeaderStorage, - Sqlite::TransactionInterface &transactionsInterface, - ProgressCounter &progressCounter) - : m_taskScheduler(taskScheduler), - m_precompiledHeaderStorage(precompiledHeaderStorage), - m_transactionsInterface(transactionsInterface), - m_progressCounter(progressCounter) - {} - - void addProjectParts(V2::ProjectPartContainers &&projectParts); - void removeProjectParts(const Utils::SmallStringVector &projectsPartIds); - - void processEntries(); - - const V2::ProjectPartContainers &projectParts() const; - - std::vector<Task> createPchTasks(V2::ProjectPartContainers &&projectParts) const; - -private: - V2::ProjectPartContainers m_projectParts; - TaskSchedulerInterface<Task> &m_taskScheduler; - PrecompiledHeaderStorageInterface &m_precompiledHeaderStorage; - Sqlite::TransactionInterface &m_transactionsInterface; - ProgressCounter &m_progressCounter; -}; - -} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.cpp b/src/tools/clangpchmanagerbackend/source/projectparts.cpp index 6be06380bf..bf2235fd13 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.cpp +++ b/src/tools/clangpchmanagerbackend/source/projectparts.cpp @@ -25,7 +25,7 @@ #include "projectparts.h" -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> #include <algorithm> @@ -33,7 +33,7 @@ namespace ClangBackEnd { inline namespace Pch { -V2::ProjectPartContainers ProjectParts::update(V2::ProjectPartContainers &&projectsParts) +ProjectPartContainers ProjectParts::update(ProjectPartContainers &&projectsParts) { auto updatedProjectPartContainers = newProjectParts(std::move(projectsParts)); @@ -44,7 +44,7 @@ V2::ProjectPartContainers ProjectParts::update(V2::ProjectPartContainers &&proje void ProjectParts::remove(const Utils::SmallStringVector &ids) { - auto shouldRemove = [&] (const V2::ProjectPartContainer &projectPart) { + auto shouldRemove = [&] (const ProjectPartContainer &projectPart) { return std::find(ids.begin(), ids.end(), projectPart.projectPartId) != ids.end(); }; @@ -52,23 +52,23 @@ void ProjectParts::remove(const Utils::SmallStringVector &ids) m_projectParts.erase(newEnd, m_projectParts.end()); } -V2::ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector &projectPartIds) const +ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector &projectPartIds) const { - V2::ProjectPartContainers projectPartsWithIds; + ProjectPartContainers projectPartsWithIds; std::copy_if(m_projectParts.begin(), m_projectParts.end(), std::back_inserter(projectPartsWithIds), - [&] (const V2::ProjectPartContainer &projectPart) { + [&] (const ProjectPartContainer &projectPart) { return std::binary_search(projectPartIds.begin(), projectPartIds.end(), projectPart.projectPartId); }); return projectPartsWithIds; } -V2::ProjectPartContainers ProjectParts::newProjectParts(V2::ProjectPartContainers &&projectsParts) const +ProjectPartContainers ProjectParts::newProjectParts(ProjectPartContainers &&projectsParts) const { - V2::ProjectPartContainers updatedProjectPartContainers; + ProjectPartContainers updatedProjectPartContainers; updatedProjectPartContainers.reserve(projectsParts.size()); std::set_difference(std::make_move_iterator(projectsParts.begin()), @@ -80,12 +80,12 @@ V2::ProjectPartContainers ProjectParts::newProjectParts(V2::ProjectPartContainer return updatedProjectPartContainers; } -void ProjectParts::mergeProjectParts(const V2::ProjectPartContainers &projectsParts) +void ProjectParts::mergeProjectParts(const ProjectPartContainers &projectsParts) { - V2::ProjectPartContainers newProjectParts; + ProjectPartContainers newProjectParts; newProjectParts.reserve(m_projectParts.size() + projectsParts.size()); - auto compare = [] (const V2::ProjectPartContainer &first, const V2::ProjectPartContainer &second) { + auto compare = [] (const ProjectPartContainer &first, const ProjectPartContainer &second) { return first.projectPartId < second.projectPartId; }; @@ -99,7 +99,7 @@ void ProjectParts::mergeProjectParts(const V2::ProjectPartContainers &projectsPa m_projectParts = newProjectParts; } -const V2::ProjectPartContainers &ProjectParts::projectParts() const +const ProjectPartContainers &ProjectParts::projectParts() const { return m_projectParts; } diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.h b/src/tools/clangpchmanagerbackend/source/projectparts.h index c0d9c61e7f..dfe03fa037 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.h +++ b/src/tools/clangpchmanagerbackend/source/projectparts.h @@ -38,17 +38,17 @@ inline namespace Pch { class ProjectParts final : public ProjectPartsInterface { public: - V2::ProjectPartContainers update(V2::ProjectPartContainers &&projectsParts) override; + ProjectPartContainers update(ProjectPartContainers &&projectsParts) override; void remove(const Utils::SmallStringVector &projectPartIds) override; - V2::ProjectPartContainers projects(const Utils::SmallStringVector &projectPartIds) const override; + ProjectPartContainers projects(const Utils::SmallStringVector &projectPartIds) const override; unittest_public: - V2::ProjectPartContainers newProjectParts(V2::ProjectPartContainers &&projectsParts) const; - void mergeProjectParts(const V2::ProjectPartContainers &projectsParts); - const V2::ProjectPartContainers &projectParts() const; + ProjectPartContainers newProjectParts(ProjectPartContainers &&projectsParts) const; + void mergeProjectParts(const ProjectPartContainers &projectsParts); + const ProjectPartContainers &projectParts() const; private: - V2::ProjectPartContainers m_projectParts; + ProjectPartContainers m_projectParts; }; } // namespace Pch diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h b/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h index 97d6c5bfc2..f84ad98090 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h @@ -25,7 +25,7 @@ #pragma once -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> namespace ClangBackEnd { @@ -36,9 +36,9 @@ public: ProjectPartsInterface(const ProjectPartsInterface &) = delete; ProjectPartsInterface &operator=(const ProjectPartsInterface &) = delete; - virtual V2::ProjectPartContainers update(V2::ProjectPartContainers &&projectsParts) = 0; + virtual ProjectPartContainers update(ProjectPartContainers &&projectsParts) = 0; virtual void remove(const Utils::SmallStringVector &projectPartIds) = 0; - virtual V2::ProjectPartContainers projects(const Utils::SmallStringVector &projectPartIds) const = 0; + virtual ProjectPartContainers projects(const Utils::SmallStringVector &projectPartIds) const = 0; protected: ~ProjectPartsInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/sourceentry.h b/src/tools/clangpchmanagerbackend/source/sourceentry.h index 3cc0fb455a..e903baf3f6 100644 --- a/src/tools/clangpchmanagerbackend/source/sourceentry.h +++ b/src/tools/clangpchmanagerbackend/source/sourceentry.h @@ -56,41 +56,81 @@ public: int64 value = -1; }; -class SourceEntry +class SourceTimeStamp { +protected: using int64 = long long; public: + SourceTimeStamp(int sourceId, int64 lastModified) + : lastModified(lastModified) + , sourceId(sourceId) + {} + + SourceTimeStamp(FilePathId sourceId, TimeStamp lastModified) + : lastModified(lastModified) + , sourceId(sourceId) + {} + + friend bool operator<(SourceTimeStamp first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + + friend bool operator<(SourceTimeStamp first, FilePathId second) + { + return first.sourceId < second; + } + + friend bool operator<(FilePathId first, SourceTimeStamp second) + { + return first < second.sourceId; + } + + friend bool operator==(SourceTimeStamp first, SourceTimeStamp second) + { + return first.sourceId == second.sourceId && first.lastModified == second.lastModified; + } + + friend bool operator!=(SourceTimeStamp first, SourceTimeStamp second) + { + return !(first == second); + } + +public: + TimeStamp lastModified; + FilePathId sourceId; +}; + +using SourceTimeStamps = std::vector<SourceTimeStamp>; + +class SourceEntry : public SourceTimeStamp +{ + +public: SourceEntry(int sourceId, int64 lastModified, int sourceType) - : lastModified(lastModified), - sourceId(sourceId), - sourceType(static_cast<SourceType>(sourceType)) + : SourceTimeStamp(sourceId, lastModified) + , sourceType(static_cast<SourceType>(sourceType)) {} SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp lastModified) - : lastModified(lastModified), - sourceId(sourceId), - sourceType(sourceType) + : SourceTimeStamp(sourceId, lastModified) + , sourceType(sourceType) {} - friend - bool operator<(SourceEntry first, SourceEntry second) + friend bool operator<(SourceEntry first, SourceEntry second) { return first.sourceId < second.sourceId; } - friend - bool operator==(SourceEntry first, SourceEntry second) + friend bool operator==(SourceEntry first, SourceEntry second) { - return first.sourceId == second.sourceId - && first.sourceType == second.sourceType - && first.lastModified == second.lastModified ; + return first.sourceId == second.sourceId && first.sourceType == second.sourceType + && first.lastModified == second.lastModified; } friend bool operator!=(SourceEntry first, SourceEntry second) { return !(first == second); } public: - TimeStamp lastModified; - FilePathId sourceId; SourceType sourceType = SourceType::UserInclude; }; diff --git a/src/tools/clangpchmanagerbackend/source/taskscheduler.h b/src/tools/clangpchmanagerbackend/source/taskscheduler.h index e2891a1163..621baef090 100644 --- a/src/tools/clangpchmanagerbackend/source/taskscheduler.h +++ b/src/tools/clangpchmanagerbackend/source/taskscheduler.h @@ -56,6 +56,8 @@ class ProcessorManagerInterface; class QueueInterface; class SymbolStorageInterface; +enum class CallDoInMainThreadAfterFinished : char { Yes, No }; + template <typename ProcessorManager, typename Task> class TaskScheduler : public TaskSchedulerInterface<Task> @@ -68,23 +70,22 @@ public: QueueInterface &queue, ProgressCounter &progressCounter, uint hardwareConcurrency, + CallDoInMainThreadAfterFinished callDoInMainThreadAfterFinished, std::launch launchPolicy = std::launch::async) - : m_processorManager(processorManager), - m_queue(queue), - m_progressCounter(progressCounter), - m_hardwareConcurrency(hardwareConcurrency), - m_launchPolicy(launchPolicy) + : m_processorManager(processorManager) + , m_queue(queue) + , m_progressCounter(progressCounter) + , m_hardwareConcurrency(hardwareConcurrency) + , m_launchPolicy(launchPolicy) + , m_callDoInMainThreadAfterFinished(callDoInMainThreadAfterFinished) {} void addTasks(std::vector<Task> &&tasks) { for (auto &task : tasks) { - auto callWrapper = [&, task=std::move(task)] (auto processor) - -> ProcessorInterface& { + auto callWrapper = [&, task = std::move(task)](auto processor) -> ProcessorInterface & { task(processor.get()); - executeInLoop([&] { - m_queue.processEntries(); - }); + executeInLoop([&] { m_queue.processEntries(); }); return processor; }; @@ -130,9 +131,10 @@ private: auto split = std::partition(m_futures.begin(), m_futures.end(), notReady); - std::for_each(split, m_futures.end(), [] (Future &future) { + std::for_each(split, m_futures.end(), [&] (Future &future) { ProcessorInterface &processor = future.get(); - processor.doInMainThreadAfterFinished(); + if (m_callDoInMainThreadAfterFinished == CallDoInMainThreadAfterFinished::Yes) + processor.doInMainThreadAfterFinished(); processor.setIsUsed(false); processor.clear(); }); @@ -191,6 +193,7 @@ private: uint m_hardwareConcurrency; std::launch m_launchPolicy; bool m_isDisabled = false; + CallDoInMainThreadAfterFinished m_callDoInMainThreadAfterFinished; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/toolchainargumentscache.h b/src/tools/clangpchmanagerbackend/source/toolchainargumentscache.h new file mode 100644 index 0000000000..4921b29a21 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/toolchainargumentscache.h @@ -0,0 +1,187 @@ +/**************************************************************************** +** +** 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 <projectpartcontainer.h> + +#include <functional> + +namespace ClangBackEnd { + +struct ArgumentsEntry +{ + ArgumentsEntry(Utils::SmallStringVector &&ids, const Utils::SmallStringVector &arguments) + : ids(std::move(ids)) + , arguments(arguments) + {} + + ArgumentsEntry(const Utils::SmallStringVector &ids, const Utils::SmallStringVector &arguments) + : ids(ids) + , arguments(arguments) + {} + + void mergeIds(Utils::SmallStringVector &&newIds) + { + Utils::SmallStringVector mergedIds; + mergedIds.reserve(ids.size() + newIds.size()); + + std::set_union(std::make_move_iterator(ids.begin()), + std::make_move_iterator(ids.end()), + std::make_move_iterator(newIds.begin()), + std::make_move_iterator(newIds.end()), + std::back_inserter(mergedIds)); + + ids = mergedIds; + } + + void removeIds(const Utils::SmallStringVector &idsToBeRemoved) + { + Utils::SmallStringVector idsWithout; + idsWithout.reserve(ids.size()); + std::set_difference(std::make_move_iterator(ids.begin()), + std::make_move_iterator(ids.end()), + idsToBeRemoved.begin(), + idsToBeRemoved.end(), + std::back_inserter(idsWithout)); + + ids = idsWithout; + } + + Utils::SmallStringVector ids; + Utils::SmallStringVector arguments; +}; + +using ArgumentsEntries = std::vector<ArgumentsEntry>; + +class ToolChainsArgumentsCache +{ +public: + void update(const ProjectPartContainers &projectParts, + const Utils::SmallStringVector &arguments) + { + struct Compare + { + bool operator()(const ArgumentsEntry &entry, const Utils::SmallStringVector &arguments) + { + return entry.arguments < arguments; + } + + bool operator()(const Utils::SmallStringVector &arguments, const ArgumentsEntry &entry) + { + return arguments < entry.arguments; + } + }; + + auto found = std::lower_bound(m_argumentEntries.begin(), + m_argumentEntries.end(), + arguments, + Compare{}); + + if (found != m_argumentEntries.end() && found->arguments == arguments) { + auto ids = createIds(projectParts); + auto removeIds = [&] (ArgumentsEntry &entry) { + entry.removeIds(ids); + }; + std::for_each(m_argumentEntries.begin(), found, removeIds); + std::for_each(std::next(found), m_argumentEntries.end(), removeIds); + found->mergeIds(std::move(ids)); + } else { + auto ids = createIds(projectParts); + for (ArgumentsEntry &entry : m_argumentEntries) + entry.removeIds(ids); + found = m_argumentEntries.emplace(found, std::move(ids), arguments); + } + + removeEmptyEntries(); + } + + void remove(const Utils::SmallStringVector &idsToBeRemoved) + { + ArgumentsEntries entries; + for (ArgumentsEntry &entry : m_argumentEntries) { + Utils::SmallStringVector usedIds; + std::set_difference(entry.ids.begin(), + entry.ids.end(), + idsToBeRemoved.begin(), + idsToBeRemoved.end(), + std::back_inserter(usedIds)); + + entry.ids = std::move(usedIds); + } + + removeEmptyEntries(); + } + + ArgumentsEntries arguments(const Utils::SmallStringVector &ids) const + { + ArgumentsEntries entries; + for (const ArgumentsEntry &entry : m_argumentEntries) { + Utils::SmallStringVector usedIds; + std::set_intersection(entry.ids.begin(), + entry.ids.end(), + ids.begin(), + ids.end(), + std::back_inserter(usedIds)); + + if (!usedIds.empty()) + entries.emplace_back(usedIds, entry.arguments); + } + + return entries; + } + + std::size_t size() const + { + return m_argumentEntries.size(); + } + +private: + static Utils::SmallStringVector createIds(const ProjectPartContainers &projectParts) + { + Utils::SmallStringVector ids; + ids.reserve(projectParts.size()); + for (const auto &projectPart : projectParts) + ids.emplace_back(projectPart.projectPartId); + + std::sort(ids.begin(), ids.end()); + + return ids; + } + + void removeEmptyEntries() + { + auto newEnd = std::remove_if(m_argumentEntries.begin(), + m_argumentEntries.end(), + [](const auto &entry) { return entry.ids.empty(); }); + + m_argumentEntries.erase(newEnd, m_argumentEntries.end()); + } + +private: + std::vector<ArgumentsEntry> m_argumentEntries; +}; + +} diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index 459eab6282..05e6a8eaf6 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -52,6 +52,8 @@ public: { systemIncludes.reserve(includes.size()); projectIncludes.reserve(includes.size()); + topSystemIncludes.reserve(includes.size() / 10); + topProjectIncludes.reserve(includes.size() / 10); for (SourceEntry include : includes) filterInclude(include); @@ -76,10 +78,16 @@ private: { switch (include.sourceType) { case SourceType::TopSystemInclude: + topSystemIncludes.emplace_back(include.sourceId); + systemIncludes.emplace_back(include.sourceId); + break; case SourceType::SystemInclude: systemIncludes.emplace_back(include.sourceId); break; case SourceType::TopProjectInclude: + topProjectIncludes.emplace_back(include.sourceId); + projectIncludes.emplace_back(include.sourceId); + break; case SourceType::ProjectInclude: projectIncludes.emplace_back(include.sourceId); break; @@ -173,6 +181,8 @@ private: public: FilePathIds projectIncludes; FilePathIds systemIncludes; + FilePathIds topProjectIncludes; + FilePathIds topSystemIncludes; UsedMacros projectUsedMacros; UsedMacros systemUsedMacros; CompilerMacros projectCompilerMacros; diff --git a/src/tools/clangrefactoringbackend/source/clangtool.cpp b/src/tools/clangrefactoringbackend/source/clangtool.cpp index e2df298c8d..dea6e1190a 100644 --- a/src/tools/clangrefactoringbackend/source/clangtool.cpp +++ b/src/tools/clangrefactoringbackend/source/clangtool.cpp @@ -50,9 +50,9 @@ void ClangTool::addFile(std::string &&directory, std::vector<std::string> &&commandLine) { m_fileContents.emplace_back(toNativePath(std::move(directory)), - std::move(fileName), - std::move(content), - std::move(commandLine)); + std::move(fileName), + std::move(content), + std::move(commandLine)); const auto &fileContent = m_fileContents.back(); @@ -140,4 +140,13 @@ clang::tooling::ClangTool ClangTool::createTool() const return tool; } +clang::tooling::ClangTool ClangTool::createOutputTool() const +{ + clang::tooling::ClangTool tool = createTool(); + + tool.clearArgumentsAdjusters(); + + return tool; +} + } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/clangtool.h b/src/tools/clangrefactoringbackend/source/clangtool.h index 9f0676a397..deee71599b 100644 --- a/src/tools/clangrefactoringbackend/source/clangtool.h +++ b/src/tools/clangrefactoringbackend/source/clangtool.h @@ -91,6 +91,7 @@ public: void addUnsavedFiles(const V2::FileContainers &unsavedFiles); clang::tooling::ClangTool createTool() const; + clang::tooling::ClangTool createOutputTool() const; private: RefactoringCompilationDatabase m_compilationDatabase; diff --git a/src/tools/clangrefactoringbackend/source/projectpartartefact.cpp b/src/tools/clangrefactoringbackend/source/projectpartartefact.cpp index 13856e1411..1c62bec8fe 100644 --- a/src/tools/clangrefactoringbackend/source/projectpartartefact.cpp +++ b/src/tools/clangrefactoringbackend/source/projectpartartefact.cpp @@ -33,16 +33,7 @@ namespace ClangBackEnd { -ProjectPartArtefact::ProjectPartArtefact(Utils::SmallStringView compilerArgumentsText, - Utils::SmallStringView compilerMacrosText, - Utils::SmallStringView includeSearchPaths, - int projectPartId) - : compilerArguments(toStringVector(compilerArgumentsText)), - compilerMacros(toCompilerMacros(compilerMacrosText)), - includeSearchPaths(toStringVector(includeSearchPaths)), - projectPartId(projectPartId) -{ -} + Utils::SmallStringVector ProjectPartArtefact::toStringVector(Utils::SmallStringView jsonText) { @@ -58,19 +49,35 @@ Utils::SmallStringVector ProjectPartArtefact::toStringVector(Utils::SmallStringV CompilerMacros ProjectPartArtefact::createCompilerMacrosFromDocument(const QJsonDocument &document) { - QJsonObject object = document.object(); + QJsonArray array = document.array(); CompilerMacros macros; - macros.reserve(object.size()); + macros.reserve(array.size()); - int index = 0; - for (auto current = object.constBegin(); current != object.constEnd(); ++current) - macros.emplace_back(current.key(), current.value().toString(), ++index); + for (const QJsonValueRef entry : array) { + const QJsonArray entryArray = entry.toArray(); + macros.emplace_back( + entryArray[0].toString(), entryArray[1].toString(), entryArray[2].toInt()); + } std::sort(macros.begin(), macros.end()); return macros; } +IncludeSearchPaths ProjectPartArtefact::createIncludeSearchPathsFromDocument(const QJsonDocument &document) +{ + QJsonArray array = document.array(); + IncludeSearchPaths paths; + paths.reserve(array.size()); + + for (const QJsonValueRef entry : array) { + const QJsonArray entryArray = entry.toArray(); + paths.emplace_back(entryArray[0].toString(), entryArray[1].toInt(), entryArray[2].toInt()); + } + + return paths; +} + CompilerMacros ProjectPartArtefact::toCompilerMacros(Utils::SmallStringView jsonText) { if (jsonText.isEmpty()) @@ -93,6 +100,17 @@ QJsonDocument ProjectPartArtefact::createJsonDocument(Utils::SmallStringView jso return document; } +IncludeSearchPaths ProjectPartArtefact::toIncludeSearchPaths(Utils::SmallStringView jsonText) +{ + + if (jsonText.isEmpty()) + return {}; + + QJsonDocument document = createJsonDocument(jsonText, "Include search paths parsing error"); + + return createIncludeSearchPathsFromDocument(document); +} + void ProjectPartArtefact::checkError(const char *whatError, const QJsonParseError &error) { if (error.error != QJsonParseError::NoError) { @@ -104,7 +122,9 @@ void ProjectPartArtefact::checkError(const char *whatError, const QJsonParseErro bool operator==(const ProjectPartArtefact &first, const ProjectPartArtefact &second) { return first.compilerArguments == second.compilerArguments - && first.compilerMacros == second.compilerMacros; + && first.compilerMacros == second.compilerMacros + && first.systemIncludeSearchPaths == second.systemIncludeSearchPaths + && first.projectIncludeSearchPaths == second.projectIncludeSearchPaths; } } // namespace ClangBackEnd diff --git a/src/tools/clangrefactoringbackend/source/projectpartartefact.h b/src/tools/clangrefactoringbackend/source/projectpartartefact.h index ee508abe27..44ca9acadb 100644 --- a/src/tools/clangrefactoringbackend/source/projectpartartefact.h +++ b/src/tools/clangrefactoringbackend/source/projectpartartefact.h @@ -30,6 +30,7 @@ #include <utils/smallstringvector.h> #include <compilermacro.h> +#include <includesearchpath.h> QT_FORWARD_DECLARE_CLASS(QJsonDocument) QT_FORWARD_DECLARE_STRUCT(QJsonParseError) @@ -41,27 +42,30 @@ class ProjectPartArtefact public: ProjectPartArtefact(Utils::SmallStringView compilerArgumentsText, Utils::SmallStringView compilerMacrosText, - Utils::SmallStringView includeSearchPaths, - int projectPartId); + Utils::SmallStringView systemIncludeSearchPathsText, + Utils::SmallStringView projectIncludeSearchPathsText, + int projectPartId) + : compilerArguments(toStringVector(compilerArgumentsText)) + , compilerMacros(toCompilerMacros(compilerMacrosText)) + , systemIncludeSearchPaths(toIncludeSearchPaths(systemIncludeSearchPathsText)) + , projectIncludeSearchPaths(toIncludeSearchPaths(projectIncludeSearchPathsText)) + , projectPartId(projectPartId) + {} - static - Utils::SmallStringVector toStringVector(Utils::SmallStringView jsonText); - static - CompilerMacros createCompilerMacrosFromDocument(const QJsonDocument &document); - static - CompilerMacros toCompilerMacros(Utils::SmallStringView jsonText); - static - QJsonDocument createJsonDocument(Utils::SmallStringView jsonText, - const char *whatError); - static - void checkError(const char *whatError, const QJsonParseError &error); - friend - bool operator==(const ProjectPartArtefact &first, const ProjectPartArtefact &second); + static Utils::SmallStringVector toStringVector(Utils::SmallStringView jsonText); + static CompilerMacros createCompilerMacrosFromDocument(const QJsonDocument &document); + static IncludeSearchPaths createIncludeSearchPathsFromDocument(const QJsonDocument &document); + static CompilerMacros toCompilerMacros(Utils::SmallStringView jsonText); + static QJsonDocument createJsonDocument(Utils::SmallStringView jsonText, const char *whatError); + static IncludeSearchPaths toIncludeSearchPaths(Utils::SmallStringView jsonText); + static void checkError(const char *whatError, const QJsonParseError &error); + friend bool operator==(const ProjectPartArtefact &first, const ProjectPartArtefact &second); public: Utils::SmallStringVector compilerArguments; CompilerMacros compilerMacros; - Utils::SmallStringVector includeSearchPaths; + IncludeSearchPaths systemIncludeSearchPaths; + IncludeSearchPaths projectIncludeSearchPaths; int projectPartId = -1; }; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp index 47a02e9fa3..0a45d361d9 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp @@ -25,8 +25,10 @@ #include "symbolindexer.h" -#include <symbolscollectorinterface.h> -#include <symbolindexertaskqueue.h> +#include "symbolscollectorinterface.h" +#include "symbolindexertaskqueue.h" + +#include <commandlinebuilder.h> #include <chrono> #include <iostream> @@ -65,7 +67,7 @@ SymbolIndexer::SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQ Sqlite::TransactionInterface &transactionInterface) : m_symbolIndexerTaskQueue(symbolIndexerTaskQueue), m_symbolStorage(symbolStorage), - m_usedMacroAndSourceStorage(usedMacroAndSourceStorage), + m_buildDependencyStorage(usedMacroAndSourceStorage), m_pathWatcher(pathWatcher), m_filePathCache(filePathCache), m_fileStatusCache(fileStatusCache), @@ -74,20 +76,22 @@ SymbolIndexer::SymbolIndexer(SymbolIndexerTaskQueueInterface &symbolIndexerTaskQ pathWatcher.setNotifier(this); } -void SymbolIndexer::updateProjectParts(V2::ProjectPartContainers &&projectParts) +void SymbolIndexer::updateProjectParts(ProjectPartContainers &&projectParts) { - for (V2::ProjectPartContainer &projectPart : projectParts) + for (ProjectPartContainer &projectPart : projectParts) updateProjectPart(std::move(projectPart)); } -void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart) +void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) { Sqlite::ImmediateTransaction transaction{m_transactionInterface}; const auto optionalArtefact = m_symbolStorage.fetchProjectPartArtefact(projectPart.projectPartId); - int projectPartId = m_symbolStorage.insertOrUpdateProjectPart(projectPart.projectPartId, - projectPart.arguments, - projectPart.compilerMacros, - projectPart.includeSearchPaths); + int projectPartId = m_symbolStorage.insertOrUpdateProjectPart( + projectPart.projectPartId, + projectPart.toolChainArguments, + projectPart.compilerMacros, + projectPart.systemIncludeSearchPaths, + projectPart.projectIncludeSearchPaths); if (optionalArtefact) projectPartId = optionalArtefact->projectPartId; const Utils::optional<ProjectPartPch> optionalProjectPartPch = m_symbolStorage.fetchPrecompiledHeader(projectPartId); @@ -97,14 +101,20 @@ void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart) if (sourcePathIds.empty()) return; - const Utils::SmallStringVector arguments = compilerArguments(projectPart.arguments, - optionalProjectPartPch); + using Builder = CommandLineBuilder<ProjectPartContainer, Utils::SmallStringVector>; + Builder commandLineBuilder{projectPart, + projectPart.toolChainArguments, + {}, + {}, + optionalProjectPartPch + ? FilePathView{optionalProjectPartPch.value().pchPath} + : FilePathView{}}; std::vector<SymbolIndexerTask> symbolIndexerTask; symbolIndexerTask.reserve(projectPart.sourcePathIds.size()); for (FilePathId sourcePathId : projectPart.sourcePathIds) { - auto indexing = [projectPartId, arguments, sourcePathId, this] - (SymbolsCollectorInterface &symbolsCollector) { + auto indexing = [projectPartId, arguments = commandLineBuilder.commandLine, sourcePathId, this]( + SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(sourcePathId, arguments); symbolsCollector.collectSymbols(); @@ -114,14 +124,14 @@ void SymbolIndexer::updateProjectPart(V2::ProjectPartContainer &&projectPart) m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), symbolsCollector.sourceLocations()); - m_symbolStorage.updateProjectPartSources(projectPartId, - symbolsCollector.sourceFiles()); + m_symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles()); - m_usedMacroAndSourceStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); + m_buildDependencyStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_usedMacroAndSourceStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_buildDependencyStorage.insertFileStatuses(symbolsCollector.fileStatuses()); - m_usedMacroAndSourceStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies()); + m_buildDependencyStorage.insertOrUpdateSourceDependencies( + symbolsCollector.sourceDependencies()); transaction.commit(); }; @@ -155,22 +165,23 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, m_fileStatusCache.update(filePathId); Sqlite::DeferredTransaction transaction{m_transactionInterface}; - const Utils::optional<ProjectPartArtefact> optionalArtefact = m_symbolStorage.fetchProjectPartArtefact(filePathId); + const Utils::optional<ProjectPartArtefact> optionalArtefact = m_symbolStorage.fetchProjectPartArtefact( + filePathId); if (!optionalArtefact) return; - const Utils::optional<ProjectPartPch> optionalProjectPartPch = m_symbolStorage.fetchPrecompiledHeader(optionalArtefact->projectPartId); + const Utils::optional<ProjectPartPch> optionalProjectPartPch = m_symbolStorage.fetchPrecompiledHeader( + optionalArtefact->projectPartId); transaction.commit(); if (!optionalArtefact.value().compilerArguments.empty()) { - const ProjectPartArtefact &artefact = optionalArtefact.value(); const Utils::SmallStringVector arguments = compilerArguments(artefact.compilerArguments, optionalProjectPartPch); - auto indexing = [projectPartId=artefact.projectPartId, arguments, filePathId, this] - (SymbolsCollectorInterface &symbolsCollector) { + auto indexing = [projectPartId = artefact.projectPartId, arguments, filePathId, this]( + SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(filePathId, arguments); symbolsCollector.collectSymbols(); @@ -182,39 +193,43 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, m_symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles()); - m_usedMacroAndSourceStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); + m_buildDependencyStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_usedMacroAndSourceStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_buildDependencyStorage.insertFileStatuses(symbolsCollector.fileStatuses()); - m_usedMacroAndSourceStorage.insertOrUpdateSourceDependencies(symbolsCollector.sourceDependencies()); + m_buildDependencyStorage.insertOrUpdateSourceDependencies( + symbolsCollector.sourceDependencies()); transaction.commit(); }; - symbolIndexerTask.emplace_back(filePathId, optionalArtefact->projectPartId, std::move(indexing)); + symbolIndexerTask.emplace_back(filePathId, + optionalArtefact->projectPartId, + std::move(indexing)); } } bool SymbolIndexer::compilerMacrosOrIncludeSearchPathsAreDifferent( - const V2::ProjectPartContainer &projectPart, + const ProjectPartContainer &projectPart, const Utils::optional<ProjectPartArtefact> &optionalArtefact) const { if (optionalArtefact) { const ProjectPartArtefact &artefact = optionalArtefact.value(); return projectPart.compilerMacros != artefact.compilerMacros - || projectPart.includeSearchPaths != artefact.includeSearchPaths; + || projectPart.systemIncludeSearchPaths != artefact.systemIncludeSearchPaths + || projectPart.projectIncludeSearchPaths != artefact.projectIncludeSearchPaths; } return true; } -FilePathIds SymbolIndexer::filterChangedFiles(const V2::ProjectPartContainer &projectPart) const +FilePathIds SymbolIndexer::filterChangedFiles(const ProjectPartContainer &projectPart) const { FilePathIds ids; ids.reserve(projectPart.sourcePathIds.size()); for (const FilePathId &sourceId : projectPart.sourcePathIds) { - long long oldLastModified = m_usedMacroAndSourceStorage.fetchLowestLastModifiedTime(sourceId); + long long oldLastModified = m_buildDependencyStorage.fetchLowestLastModifiedTime(sourceId); long long currentLastModified = m_fileStatusCache.lastModifiedTime(sourceId); if (oldLastModified < currentLastModified) ids.push_back(sourceId); @@ -223,7 +238,7 @@ FilePathIds SymbolIndexer::filterChangedFiles(const V2::ProjectPartContainer &pr return ids; } -FilePathIds SymbolIndexer::updatableFilePathIds(const V2::ProjectPartContainer &projectPart, +FilePathIds SymbolIndexer::updatableFilePathIds(const ProjectPartContainer &projectPart, const Utils::optional<ProjectPartArtefact> &optionalArtefact) const { if (compilerMacrosOrIncludeSearchPathsAreDifferent(projectPart, optionalArtefact)) @@ -233,8 +248,8 @@ FilePathIds SymbolIndexer::updatableFilePathIds(const V2::ProjectPartContainer & } Utils::SmallStringVector SymbolIndexer::compilerArguments( - Utils::SmallStringVector arguments, - const Utils::optional<ProjectPartPch> optionalProjectPartPch) const + Utils::SmallStringVector arguments, + const Utils::optional<ProjectPartPch> optionalProjectPartPch) const { if (optionalProjectPartPch) { arguments.emplace_back("-Xclang"); diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.h b/src/tools/clangrefactoringbackend/source/symbolindexer.h index d9070005ce..55f62ffa5f 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.h @@ -31,7 +31,7 @@ #include "builddependenciesstorageinterface.h" #include "clangpathwatcher.h" -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> #include <filecontainerv2.h> namespace ClangBackEnd { @@ -49,8 +49,8 @@ public: FileStatusCache &fileStatusCache, Sqlite::TransactionInterface &transactionInterface); - void updateProjectParts(V2::ProjectPartContainers &&projectParts); - void updateProjectPart(V2::ProjectPartContainer &&projectPart); + void updateProjectParts(ProjectPartContainers &&projectParts); + void updateProjectPart(ProjectPartContainer &&projectPart); void pathsWithIdsChanged(const Utils::SmallStringVector &ids) override; void pathsChanged(const FilePathIds &filePathIds) override; @@ -58,22 +58,23 @@ public: std::vector<SymbolIndexerTask> &symbolIndexerTask); bool compilerMacrosOrIncludeSearchPathsAreDifferent( - const V2::ProjectPartContainer &projectPart, + const ProjectPartContainer &projectPart, const Utils::optional<ProjectPartArtefact> &optionalArtefact) const; FilePathIds filterChangedFiles( - const V2::ProjectPartContainer &projectPart) const; + const ProjectPartContainer &projectPart) const; - FilePathIds updatableFilePathIds(const V2::ProjectPartContainer &projectPart, + FilePathIds updatableFilePathIds(const ProjectPartContainer &projectPart, const Utils::optional<ProjectPartArtefact> &optionalArtefact) const; - Utils::SmallStringVector compilerArguments(Utils::SmallStringVector arguments, - const Utils::optional<ProjectPartPch> optionalProjectPartPch) const; + Utils::SmallStringVector compilerArguments( + Utils::SmallStringVector arguments, + const Utils::optional<ProjectPartPch> optionalProjectPartPch) const; private: SymbolIndexerTaskQueueInterface &m_symbolIndexerTaskQueue; SymbolStorageInterface &m_symbolStorage; - BuildDependenciesStorageInterface &m_usedMacroAndSourceStorage; + BuildDependenciesStorageInterface &m_buildDependencyStorage; ClangPathWatcherInterface &m_pathWatcher; FilePathCachingInterface &m_filePathCache; FileStatusCache &m_fileStatusCache; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.cpp b/src/tools/clangrefactoringbackend/source/symbolindexing.cpp index 4f62b859f0..529396e9fa 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexing.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexing.cpp @@ -27,7 +27,7 @@ namespace ClangBackEnd { -void SymbolIndexing::updateProjectParts(V2::ProjectPartContainers &&projectParts) +void SymbolIndexing::updateProjectParts(ProjectPartContainers &&projectParts) { m_indexer.updateProjectParts(std::move(projectParts)); } diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h index 10e1be0358..6f52f863d8 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexing.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h @@ -81,12 +81,16 @@ public: FilePathCachingInterface &filePathCache, const GeneratedFiles &generatedFiles, ProgressCounter::SetProgressCallback &&setProgressCallback) - : m_filePathCache(filePathCache), - m_usedMacroAndSourceStorage(database), - m_symbolStorage(database), - m_collectorManger(generatedFiles, database), - m_progressCounter(std::move(setProgressCallback)), - m_indexerScheduler(m_collectorManger, m_indexerQueue, m_progressCounter, std::thread::hardware_concurrency()) + : m_filePathCache(filePathCache) + , m_buildDependencyStorage(database) + , m_symbolStorage(database) + , m_collectorManger(generatedFiles, database) + , m_progressCounter(std::move(setProgressCallback)) + , m_indexerScheduler(m_collectorManger, + m_indexerQueue, + m_progressCounter, + std::thread::hardware_concurrency(), + CallDoInMainThreadAfterFinished::Yes) { } @@ -109,12 +113,12 @@ public: } } - void updateProjectParts(V2::ProjectPartContainers &&projectParts) override; + void updateProjectParts(ProjectPartContainers &&projectParts) override; private: using SymbolIndexerTaskScheduler = TaskScheduler<SymbolsCollectorManager, SymbolIndexerTask::Callable>; FilePathCachingInterface &m_filePathCache; - BuildDependenciesStorage m_usedMacroAndSourceStorage; + BuildDependenciesStorage m_buildDependencyStorage; SymbolStorage m_symbolStorage; ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache}; FileStatusCache m_fileStatusCache{m_filePathCache}; @@ -124,7 +128,7 @@ private: SymbolIndexerTaskQueue m_indexerQueue{m_indexerScheduler, m_progressCounter}; SymbolIndexer m_indexer{m_indexerQueue, m_symbolStorage, - m_usedMacroAndSourceStorage, + m_buildDependencyStorage, m_sourceWatcher, m_filePathCache, m_fileStatusCache, diff --git a/src/tools/clangrefactoringbackend/source/symbolindexinginterface.h b/src/tools/clangrefactoringbackend/source/symbolindexinginterface.h index 70e16d7429..3feb9e1b9f 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexinginterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolindexinginterface.h @@ -25,7 +25,7 @@ #pragma once -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> #include <filecontainerv2.h> namespace ClangBackEnd { @@ -37,7 +37,7 @@ public: SymbolIndexingInterface(const SymbolIndexingInterface&) = delete; SymbolIndexingInterface &operator=(const SymbolIndexingInterface&) = delete; - virtual void updateProjectParts(V2::ProjectPartContainers &&projectParts) = 0; + virtual void updateProjectParts(ProjectPartContainers &&projectParts) = 0; protected: ~SymbolIndexingInterface() = default; diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index 02d52bfb50..0be04c04b6 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -31,6 +31,7 @@ #include <sqliteexception.h> #include <sqlitetransaction.h> #include <sqlitetable.h> +#include <includesearchpath.h> #include <QJsonArray> #include <QJsonDocument> @@ -68,45 +69,39 @@ public: } int insertOrUpdateProjectPart(Utils::SmallStringView projectPartName, - const Utils::SmallStringVector &commandLineArguments, - const CompilerMacros &compilerMacros, - const Utils::SmallStringVector &includeSearchPaths) override + const Utils::SmallStringVector &commandLineArguments, + const CompilerMacros &compilerMacros, + const IncludeSearchPaths &systemIncludeSearchPaths, + const IncludeSearchPaths &projectIncludeSearchPaths) override { - m_database.setLastInsertedRowId(-1); - Utils::SmallString compilerArguementsAsJson = toJson(commandLineArguments); Utils::SmallString compilerMacrosAsJson = toJson(compilerMacros); - Utils::SmallString includeSearchPathsAsJason = toJson(includeSearchPaths); - - WriteStatement &insertStatement = m_insertProjectPartStatement; - insertStatement.write(projectPartName, - compilerArguementsAsJson, - compilerMacrosAsJson, - includeSearchPathsAsJason); - - if (m_database.lastInsertedRowId() == -1) { - WriteStatement &updateStatement = m_updateProjectPartStatement; - updateStatement.write(compilerArguementsAsJson, - compilerMacrosAsJson, - includeSearchPathsAsJason, - projectPartName); - } + Utils::SmallString systemIncludeSearchPathsAsJason = toJson(systemIncludeSearchPaths); + Utils::SmallString projectIncludeSearchPathsAsJason = toJson(projectIncludeSearchPaths); + + m_insertOrUpdateProjectPartStatement.write(projectPartName, + compilerArguementsAsJson, + compilerMacrosAsJson, + systemIncludeSearchPathsAsJason, + projectIncludeSearchPathsAsJason); + + auto projectPartId = m_getProjectPartIdStatement.template value<int>(projectPartName); - return int(m_database.lastInsertedRowId()); + return projectPartId.value(); } Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(FilePathId sourceId) const override { ReadStatement &statement = m_getProjectPartArtefactsBySourceId; - return statement.template value<ProjectPartArtefact, 4>(sourceId.filePathId); + return statement.template value<ProjectPartArtefact, 5>(sourceId.filePathId); } Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(Utils::SmallStringView projectPartName) const override { ReadStatement &statement = m_getProjectPartArtefactsByProjectPartName; - return statement.template value<ProjectPartArtefact, 4>(projectPartName); + return statement.template value<ProjectPartArtefact, 5>(projectPartName); } void updateProjectPartSources(int projectPartId, @@ -137,12 +132,25 @@ public: static Utils::SmallString toJson(const CompilerMacros &compilerMacros) { QJsonDocument document; - QJsonObject object; + QJsonArray array; for (const CompilerMacro ¯o : compilerMacros) - object.insert(QString(macro.key), QString(macro.value)); + array.push_back(QJsonArray{{QString(macro.key), QString(macro.value), macro.index}}); - document.setObject(object); + document.setArray(array); + + return document.toJson(QJsonDocument::Compact); + } + + static Utils::SmallString toJson(const IncludeSearchPaths &includeSearchPaths) + { + QJsonDocument document; + QJsonArray array; + + for (const IncludeSearchPath &path : includeSearchPaths) + array.push_back(QJsonArray{{path.path.data(), path.index, int(path.type)}}); + + document.setArray(array); return document.toJson(QJsonDocument::Compact); } @@ -299,14 +307,12 @@ public: "DELETE FROM newLocations", m_database }; - WriteStatement m_insertProjectPartStatement{ - "INSERT OR IGNORE INTO projectParts(projectPartName, compilerArguments, compilerMacros, includeSearchPaths) VALUES (?,?,?,?)", - m_database - }; - WriteStatement m_updateProjectPartStatement{ - "UPDATE projectParts SET compilerArguments = ?, compilerMacros = ?, includeSearchPaths = ? WHERE projectPartName = ?", - m_database - }; + WriteStatement m_insertOrUpdateProjectPartStatement{ + "INSERT INTO projectParts(projectPartName, compilerArguments, compilerMacros, " + "systemIncludeSearchPaths, projectIncludeSearchPaths) VALUES (?001,?002,?003,?004,?005) ON " + "CONFLICT(projectPartName) DO UPDATE SET compilerArguments=?002, compilerMacros=?003, " + "systemIncludeSearchPaths=?004, projectIncludeSearchPaths=?005", + m_database}; mutable ReadStatement m_getProjectPartIdStatement{ "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", m_database @@ -324,13 +330,14 @@ public: m_database }; mutable ReadStatement m_getProjectPartArtefactsBySourceId{ - "SELECT compilerArguments, compilerMacros, includeSearchPaths, projectPartId FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM projectPartsSources WHERE sourceId = ?)", - m_database - }; + "SELECT compilerArguments, compilerMacros, systemIncludeSearchPaths, projectIncludeSearchPaths, " + "projectPartId FROM projectParts WHERE projectPartId = (SELECT projectPartId FROM " + "projectPartsSources WHERE sourceId = ?)", + m_database}; mutable ReadStatement m_getProjectPartArtefactsByProjectPartName{ - "SELECT compilerArguments, compilerMacros, includeSearchPaths, projectPartId FROM projectParts WHERE projectPartName = ?", - m_database - }; + "SELECT compilerArguments, compilerMacros, systemIncludeSearchPaths, " + "projectIncludeSearchPaths, projectPartId FROM projectParts WHERE projectPartName = ?", + m_database}; mutable ReadStatement m_getPrecompiledHeader{ "SELECT projectPchPath, projectPchBuildTime FROM precompiledHeaders WHERE projectPartId = ?", m_database diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h index 0cb1dafd4f..3e51302c20 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h @@ -34,6 +34,8 @@ #include "symbolentry.h" #include "usedmacro.h" +#include <includesearchpath.h> + #include <sqlitetransaction.h> #include <compilermacro.h> @@ -48,15 +50,20 @@ public: SymbolStorageInterface &operator=(const SymbolStorageInterface &) = delete; virtual void addSymbolsAndSourceLocations(const SymbolEntries &symbolEntries, - const SourceLocationEntries &sourceLocations) = 0; - virtual int insertOrUpdateProjectPart(Utils::SmallStringView projectPartName, - const Utils::SmallStringVector &commandLineArguments, - const CompilerMacros &compilerMacros, - const Utils::SmallStringVector &includeSearchPaths) = 0; - virtual void updateProjectPartSources(int projectPartId, - const FilePathIds &sourceFilePathIds) = 0; - virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(FilePathId sourceId) const = 0; - virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact(Utils::SmallStringView projectPartName) const = 0; + const SourceLocationEntries &sourceLocations) + = 0; + virtual int insertOrUpdateProjectPart( + Utils::SmallStringView projectPartName, + const Utils::SmallStringVector &commandLineArguments, + const CompilerMacros &compilerMacros, + const ClangBackEnd::IncludeSearchPaths &systemIncludeSearchPaths, + const ClangBackEnd::IncludeSearchPaths &projectIncludeSearchPaths) + = 0; + virtual void updateProjectPartSources(int projectPartId, const FilePathIds &sourceFilePathIds) = 0; + virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact( + FilePathId sourceId) const = 0; + virtual Utils::optional<ProjectPartArtefact> fetchProjectPartArtefact( + Utils::SmallStringView projectPartName) const = 0; virtual Utils::optional<ProjectPartPch> fetchPrecompiledHeader(int projectPartId) const = 0; protected: diff --git a/tests/unit/unittest/builddependenciesprovider-test.cpp b/tests/unit/unittest/builddependenciesprovider-test.cpp index cb39ec2bdf..2a5372c55d 100644 --- a/tests/unit/unittest/builddependenciesprovider-test.cpp +++ b/tests/unit/unittest/builddependenciesprovider-test.cpp @@ -63,18 +63,28 @@ protected: mockModifiedTimeChecker, mockBuildDependenciesGenerator, mockSqliteTransactionBackend}; - ClangBackEnd::V2::ProjectPartContainer projectPart1{"ProjectPart1", - {"--yi"}, - {{"YI", "1", 1}}, - {"/yi"}, - {1}, - {2}}; - ClangBackEnd::V2::ProjectPartContainer projectPart2{"ProjectPart2", - {"--er"}, - {{"ER", "2", 1}}, - {"/er"}, - {1}, - {2, 3, 4}}; + ClangBackEnd::ProjectPartContainer projectPart1{ + "ProjectPart1", + {"--yi"}, + {{"YI", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/project/yi", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {1}, + {2}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; + ClangBackEnd::ProjectPartContainer projectPart2{ + "ProjectPart2", + {"--er"}, + {{"ER", "2", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/project/er", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {1}, + {2, 3, 4}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; SourceEntries firstSources{{1, SourceType::UserInclude, 1}, {2, SourceType::UserInclude, 1}, {10, SourceType::UserInclude, 1}}; diff --git a/tests/unit/unittest/builddependencycollector-test.cpp b/tests/unit/unittest/builddependencycollector-test.cpp index 7a65361edb..1b42f143a0 100644 --- a/tests/unit/unittest/builddependencycollector-test.cpp +++ b/tests/unit/unittest/builddependencycollector-test.cpp @@ -529,25 +529,27 @@ TEST_F(BuildDependencyCollector, MissingInclude) TEST_F(BuildDependencyCollector, Create) { + using ClangBackEnd::IncludeSearchPathType; ClangBackEnd::BuildDependencyCollector collector{filePathCache}; - ClangBackEnd::V2::ProjectPartContainer - projectPart{"project1", - {"cc", - "-I", - TESTDATA_DIR "/builddependencycollector/external", - "-I", - TESTDATA_DIR "/builddependencycollector/project", - "-isystem", - TESTDATA_DIR "/builddependencycollector/system"}, - {}, - {}, - { - id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), - id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"), - id(TESTDATA_DIR "/builddependencycollector/project/macros.h"), - }, - {id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp")}}; + ClangBackEnd::ProjectPartContainer projectPart{ + "project1", + {}, + {}, + {{TESTDATA_DIR "/builddependencycollector/system", 1, IncludeSearchPathType::System}}, + { + {TESTDATA_DIR "/builddependencycollector/project", 1, IncludeSearchPathType::User}, + {TESTDATA_DIR "/builddependencycollector/external", 2, IncludeSearchPathType::User}, + }, + { + id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"), + id(TESTDATA_DIR "/builddependencycollector/project/macros.h"), + }, + {id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp")}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX11, + Utils::LanguageExtension::None}; auto buildDependency = collector.create(projectPart); diff --git a/tests/unit/unittest/commandlinebuilder-test.cpp b/tests/unit/unittest/commandlinebuilder-test.cpp new file mode 100644 index 0000000000..6cf673bf83 --- /dev/null +++ b/tests/unit/unittest/commandlinebuilder-test.cpp @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** 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 <commandlinebuilder.h> +#include <pchtask.h> +#include <projectpartcontainer.h> + +namespace { +template<typename ProjectInfo> +using Builder = ClangBackEnd::CommandLineBuilder<ProjectInfo>; + +using ClangBackEnd::IncludeSearchPathType; + +template <typename ProjectInfo> +class CommandLineBuilder : public testing::Test +{ +}; + +template <> +class CommandLineBuilder<ClangBackEnd::PchTask> : public testing::Test +{ +public: + CommandLineBuilder() + { + cppProjectInfo.language = Utils::Language::Cxx; + } + +public: + ClangBackEnd::PchTask emptyProjectInfo{"empty", {}, {}, {}, {}, {}, {}}; + ClangBackEnd::PchTask cppProjectInfo{"project1", {}, {}, {}, {}, {}, {}}; +}; + +template <> +class CommandLineBuilder<ClangBackEnd::ProjectPartContainer> : public testing::Test +{ +public: + CommandLineBuilder() + { + cppProjectInfo.language = Utils::Language::Cxx; + } + +public: + ClangBackEnd::ProjectPartContainer emptyProjectInfo{"empty", + {}, + {}, + {}, + {}, + {}, + {}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX98, + Utils::LanguageExtension::None}; + ClangBackEnd::ProjectPartContainer cppProjectInfo{"project1", + {}, + {}, + {}, + {}, + {}, + {}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX98, + Utils::LanguageExtension::None}; +}; + +using ProjectInfos = testing::Types<ClangBackEnd::PchTask, ClangBackEnd::ProjectPartContainer>; +TYPED_TEST_SUITE(CommandLineBuilder, ProjectInfos); + +TYPED_TEST(CommandLineBuilder, AddToolChainArguments) +{ + Builder<TypeParam> builder{this->emptyProjectInfo, {"-m64", "-PIC"}, {}}; + + ASSERT_THAT(builder.commandLine, AllOf(Contains("-m64"), Contains("-PIC"))); +} + +TYPED_TEST(CommandLineBuilder, CTask) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C11; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT( + builder.commandLine, + ElementsAre("clang", "-x", "c-header", "-std=c11", "-nostdinc", "-nostdlibinc", "/source/file.c")); +} + +TYPED_TEST(CommandLineBuilder, ObjectiveCTask) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::ObjectiveC; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C11; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang", + "-x", + "objective-c-header", + "-std=c11", + "-nostdinc", + "-nostdlibinc", + "/source/file.c")); +} + +TYPED_TEST(CommandLineBuilder, CppTask) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX98; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang++", + "-x", + "c++-header", + "-std=c++98", + "-nostdinc", + "-nostdlibinc", + "/source/file.cpp")); +} + +TYPED_TEST(CommandLineBuilder, ObjectiveCppTask) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::ObjectiveC; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX98; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang++", + "-x", + "objective-c++-header", + "-std=c++98", + "-nostdinc", + "-nostdlibinc", + "/source/file.cpp")); +} + +TYPED_TEST(CommandLineBuilder, Cpp98) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX98; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c++98")); +} + +TYPED_TEST(CommandLineBuilder, Cpp03) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX03; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c++03")); +} + +TYPED_TEST(CommandLineBuilder, Cpp11) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX11; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c++11")); +} + +TYPED_TEST(CommandLineBuilder, Cpp14) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX14; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c++14")); +} + +TYPED_TEST(CommandLineBuilder, Cpp17) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX17; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c++17")); +} + +TYPED_TEST(CommandLineBuilder, Cpp20) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX2a; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c++2a")); +} + +TYPED_TEST(CommandLineBuilder, GnuCpp98) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX98; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu++98")); +} + +TYPED_TEST(CommandLineBuilder, GnuCpp03) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX03; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu++03")); +} + +TYPED_TEST(CommandLineBuilder, GnuCpp11) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX11; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu++11")); +} + +TYPED_TEST(CommandLineBuilder, GnuCpp14) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX14; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu++14")); +} + +TYPED_TEST(CommandLineBuilder, GnuCpp17) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX17; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu++17")); +} + +TYPED_TEST(CommandLineBuilder, GnuCpp20) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX2a; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu++2a")); +} + +TYPED_TEST(CommandLineBuilder, C89) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C89; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c89")); +} + +TYPED_TEST(CommandLineBuilder, C99) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C99; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c99")); +} + +TYPED_TEST(CommandLineBuilder, C11) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C11; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c11")); +} + +TYPED_TEST(CommandLineBuilder, C18) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C18; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=c18")); +} + +TYPED_TEST(CommandLineBuilder, GnuC89) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C89; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu89")); +} + +TYPED_TEST(CommandLineBuilder, GnuC99) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C99; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu99")); +} + +TYPED_TEST(CommandLineBuilder, GnuC11) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C11; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu11")); +} + +TYPED_TEST(CommandLineBuilder, GnuC18) +{ + this->emptyProjectInfo.language = Utils::Language::C; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::C18; + this->emptyProjectInfo.languageExtension = Utils::LanguageExtension::Gnu; + + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.c"}; + + ASSERT_THAT(builder.commandLine, Contains("-std=gnu18")); +} + +TYPED_TEST(CommandLineBuilder, IncludesOrder) +{ + this->emptyProjectInfo.language = Utils::Language::Cxx; + this->emptyProjectInfo.languageVersion = Utils::LanguageVersion::CXX11; + this->emptyProjectInfo.projectIncludeSearchPaths = {{"/include/bar", 2, IncludeSearchPathType::User}, + {"/include/foo", 1, IncludeSearchPathType::User}}; + this->emptyProjectInfo.systemIncludeSearchPaths = {{"/system/bar", 4, IncludeSearchPathType::System}, + {"/system/foo", 3, IncludeSearchPathType::Framework}, + {"/builtin/bar", 2, IncludeSearchPathType::BuiltIn}, + {"/builtin/foo", 1, IncludeSearchPathType::BuiltIn}}; + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang++", + "-x", + "c++-header", + "-std=c++11", + "-nostdinc", + "-nostdlibinc", + "-I", + "/include/foo", + "-I", + "/include/bar", + "-F", + "/system/foo", + "-isystem", + "/system/bar", + "-isystem", + "/builtin/foo", + "-isystem", + "/builtin/bar", + "/source/file.cpp")); +} + +TYPED_TEST(CommandLineBuilder, EmptySourceFile) +{ + Builder<TypeParam> builder{this->emptyProjectInfo, {}, {}}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang++", "-x", "c++-header", "-std=c++98", "-nostdinc", "-nostdlibinc")); +} + +TYPED_TEST(CommandLineBuilder, SourceFile) +{ + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp"}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang++", + "-x", + "c++-header", + "-std=c++98", + "-nostdinc", + "-nostdlibinc", + "/source/file.cpp")); +} + + +TYPED_TEST(CommandLineBuilder, EmptyOutputFile) +{ + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp", ""}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang++", + "-x", + "c++-header", + "-std=c++98", + "-nostdinc", + "-nostdlibinc", + "/source/file.cpp")); +} + +TYPED_TEST(CommandLineBuilder, OutputFile) +{ + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp", "/output/file.o"}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang++", + "-x", + "c++-header", + "-std=c++98", + "-nostdinc", + "-nostdlibinc", + "-o", + "/output/file.o", + "/source/file.cpp")); +} + +TYPED_TEST(CommandLineBuilder, IncludePchPath) +{ + Builder<TypeParam> builder{this->emptyProjectInfo, {}, "/source/file.cpp", "/output/file.o", "/pch/file.pch"}; + + ASSERT_THAT(builder.commandLine, + ElementsAre("clang++", + "-x", + "c++-header", + "-std=c++98", + "-nostdinc", + "-nostdlibinc", + "-Xclang", + "-include-pch", + "-Xclang", + "/pch/file.pch", + "-o", + "/output/file.o", + "/source/file.cpp")); +} + +} // namespace diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h index fbf4e249f4..e8bbd52800 100644 --- a/tests/unit/unittest/google-using-declarations.h +++ b/tests/unit/unittest/google-using-declarations.h @@ -38,6 +38,7 @@ using testing::Assign; using testing::ByMove; using testing::ByRef; using testing::Contains; +using testing::ContainerEq; using testing::ElementsAre; using testing::Field; using testing::HasSubstr; diff --git a/tests/unit/unittest/googletest.h b/tests/unit/unittest/googletest.h index e5d221d6a8..b685b83c78 100644 --- a/tests/unit/unittest/googletest.h +++ b/tests/unit/unittest/googletest.h @@ -33,6 +33,7 @@ #include <gmock/gmock-matchers.h> #include <gtest/gtest.h> #include <gtest/gtest-printers.h> +#include <gtest/gtest-typed-test.h> #include "compare-operators.h" diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 36e9cdf891..8b2fbcd226 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -42,6 +42,7 @@ #include <filestatus.h> #include <filepath.h> #include <fulltokeninfo.h> +#include <includesearchpath.h> #include <nativefilepath.h> #include <pchcreator.h> #include <pchtask.h> @@ -56,6 +57,7 @@ #include <symbolindexertaskqueue.h> #include <symbol.h> #include <tooltipinfo.h> +#include <toolchainargumentscache.h> #include <projectpartentry.h> #include <usedmacro.h> @@ -181,6 +183,100 @@ std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn) return out << "(" << lineColumn.line << ", " << lineColumn.column << ")"; } +const char * toText(Utils::Language language) +{ + using Utils::Language; + + switch (language) { + case Language::C: + return "C"; + case Language::Cxx: + return "Cxx"; + } + + return ""; +} + +std::ostream &operator<<(std::ostream &out, const Utils::Language &language) +{ + return out << "Utils::" << toText(language); +} + +const char * toText(Utils::LanguageVersion languageVersion) +{ + using Utils::LanguageVersion; + + switch (languageVersion) { + case LanguageVersion::C11: + return "C11"; + case LanguageVersion::C18: + return "C18"; + case LanguageVersion::C89: + return "C89"; + case LanguageVersion::C99: + return "C99"; + case LanguageVersion::CXX03: + return "CXX03"; + case LanguageVersion::CXX11: + return "CXX11"; + case LanguageVersion::CXX14: + return "CXX14"; + case LanguageVersion::CXX17: + return "CXX17"; + case LanguageVersion::CXX2a: + return "CXX2a"; + case LanguageVersion::CXX98: + return "CXX98"; + } + + return ""; +} + +std::ostream &operator<<(std::ostream &out, const Utils::LanguageVersion &languageVersion) +{ + return out << "Utils::" << toText(languageVersion); +} + +const std::string toText(Utils::LanguageExtension extension, std::string prefix = {}) +{ + std::stringstream out; + using Utils::LanguageExtension; + + if (extension == LanguageExtension::None) { + out << prefix << "None"; + } else if (extension == LanguageExtension::All) { + out << prefix << "All"; + } else { + std::string split = ""; + if (extension == LanguageExtension::Gnu) { + out << prefix << "Gnu"; + split = " | "; + } + if (extension == LanguageExtension::Microsoft) { + out << split << prefix << "Microsoft"; + split = " | "; + } + if (extension == LanguageExtension::Borland) { + out << split << prefix << "Borland"; + split = " | "; + } + if (extension == LanguageExtension::OpenMP) { + out << split << prefix << "OpenMP"; + split = " | "; + } + if (extension == LanguageExtension::ObjectiveC) { + out << split << prefix << "ObjectiveC"; + } + } + + return out.str(); +} + +std::ostream &operator<<(std::ostream &out, const Utils::LanguageExtension &languageExtension) +{ + return out << toText(languageExtension, "Utils::"); +} + void PrintTo(Utils::SmallStringView text, ::std::ostream *os) { *os << "\"" << text << "\""; @@ -1061,7 +1157,15 @@ std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes) std::ostream &operator<<(std::ostream &out, const PchTask &task) { return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros - << ", " << task.usedMacros << ")"; + << ", " << task.usedMacros << ", " << toText(task.language) << ", " + << task.systemIncludeSearchPaths << ", " << task.projectIncludeSearchPaths << ", " + << task.toolChainArguments << ", " << toText(task.languageVersion) << ", " + << toText(task.languageExtension) << ")"; +} + +std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet) +{ + return out << "(" << taskSet.system << ", " << taskSet.project << ")"; } std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency) @@ -1105,6 +1209,50 @@ std::ostream &operator<<(std::ostream &out, const SourceEntry &entry) return out << "(" << entry.sourceId << ", " << sourceTypeString(entry.sourceType) << ")"; } +const char *typeToString(IncludeSearchPathType type) +{ + switch (type) { + case IncludeSearchPathType::Invalid: + return "Invalid"; + case IncludeSearchPathType::User: + return "User"; + case IncludeSearchPathType::System: + return "System"; + case IncludeSearchPathType::BuiltIn: + return "BuiltIn"; + case IncludeSearchPathType::Framework: + return "Framework"; + } + + return nullptr; +} + +std::ostream &operator<<(std::ostream &out, const IncludeSearchPathType &pathType) +{ + return out << "IncludeSearchPathType::" << typeToString(pathType); +} + +std::ostream &operator<<(std::ostream &out, const IncludeSearchPath &path) +{ + return out << "(" << path.path << ", " << path.index << ", " << typeToString(path.type) << ")"; +} + +std::ostream &operator<<(std::ostream &out, const ArgumentsEntry &entry) +{ + return out << "(" << entry.ids << ", " << entry.arguments << ")"; +} + +std::ostream &operator<<(std::ostream &out, const ProjectPartContainer &container) +{ + out << "(" << container.projectPartId << ", " << container.toolChainArguments << ", " + << container.headerPathIds << ", " << container.sourcePathIds << ", " + << container.compilerMacros << ", " << container.systemIncludeSearchPaths << ", " + << container.projectIncludeSearchPaths << ", " << toText(container.language) << ", " + << toText(container.languageVersion) << ", " << toText(container.languageExtension) << ")"; + + return out; +} + void PrintTo(const FilePath &filePath, ::std::ostream *os) { *os << filePath; @@ -1138,19 +1286,6 @@ std::ostream &operator<<(std::ostream &os, const FileContainer &container) return os; } -std::ostream &operator<<(std::ostream &out, const ProjectPartContainer &container) -{ - out << "(" - << container.projectPartId << ", " - << container.arguments << ", " - << container.headerPathIds << ", " - << container.sourcePathIds << ", " - << container.compilerMacros << ", " - << container.includeSearchPaths << ")"; - - return out; -} - std::ostream &operator<<(std::ostream &os, const SourceLocationContainer &container) { os << "(" diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index 0f2184fc11..ec54af3085 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -25,6 +25,7 @@ #pragma once +#include <utils/cpplanguage_details.h> #include <utils/smallstringio.h> #include <utils/optional.h> @@ -74,6 +75,9 @@ class LineColumn; class SmallStringView; std::ostream &operator<<(std::ostream &out, const LineColumn &lineColumn); +std::ostream &operator<<(std::ostream &out, const Utils::Language &language); +std::ostream &operator<<(std::ostream &out, const Utils::LanguageVersion &languageVersion); +std::ostream &operator<<(std::ostream &out, const Utils::LanguageExtension &languageExtension); template <typename Type> std::ostream &operator<<(std::ostream &out, const Utils::optional<Type> &optional) @@ -176,10 +180,15 @@ class SymbolIndexerTask; class ProgressMessage; class PchCreatorIncludes; class PchTask; +class PchTaskSet; class BuildDependency; class SourceEntry; class FilePathCaching; class SlotUsage; +class IncludeSearchPath; +enum class IncludeSearchPathType : unsigned char; +class ArgumentsEntry; +class ProjectPartContainer; std::ostream &operator<<(std::ostream &out, const SourceLocationEntry &entry); std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths); @@ -262,9 +271,14 @@ std::ostream &operator<<(std::ostream &out, const SymbolIndexerTask &task); std::ostream &operator<<(std::ostream &out, const ProgressMessage &message); std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes); std::ostream &operator<<(std::ostream &out, const PchTask &task); +std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet); std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency); std::ostream &operator<<(std::ostream &out, const SourceEntry &entry); std::ostream &operator<<(std::ostream &out, const SlotUsage &slotUsage); +std::ostream &operator<<(std::ostream &out, const IncludeSearchPathType &pathType); +std::ostream &operator<<(std::ostream &out, const IncludeSearchPath &path); +std::ostream &operator<<(std::ostream &out, const ArgumentsEntry &entry); +std::ostream &operator<<(std::ostream &out, const ProjectPartContainer &container); void PrintTo(const FilePath &filePath, ::std::ostream *os); void PrintTo(const FilePathView &filePathView, ::std::ostream *os); @@ -272,12 +286,10 @@ void PrintTo(const FilePathId &filePathId, ::std::ostream *os); namespace V2 { class FileContainer; -class ProjectPartContainer; class SourceRangeContainer; class SourceLocationContainer; std::ostream &operator<<(std::ostream &out, const FileContainer &container); -std::ostream &operator<<(std::ostream &out, const ProjectPartContainer &container); std::ostream &operator<<(std::ostream &out, const SourceLocationContainer &container); std::ostream &operator<<(std::ostream &out, const SourceRangeContainer &container); } // namespace V2 diff --git a/tests/unit/unittest/mockbuilddependenciesprovider.h b/tests/unit/unittest/mockbuilddependenciesprovider.h index 2a1fd8f93f..a4a57db33b 100644 --- a/tests/unit/unittest/mockbuilddependenciesprovider.h +++ b/tests/unit/unittest/mockbuilddependenciesprovider.h @@ -34,5 +34,5 @@ class MockBuildDependenciesProvider : public ClangBackEnd::BuildDependenciesProv public: MOCK_METHOD1( create, - ClangBackEnd::BuildDependency(const ClangBackEnd::V2::ProjectPartContainer &projectPart)); + ClangBackEnd::BuildDependency(const ClangBackEnd::ProjectPartContainer &projectPart)); }; diff --git a/tests/unit/unittest/mockbuilddependencygenerator.h b/tests/unit/unittest/mockbuilddependencygenerator.h index 91b8a1422d..abd6c223d0 100644 --- a/tests/unit/unittest/mockbuilddependencygenerator.h +++ b/tests/unit/unittest/mockbuilddependencygenerator.h @@ -33,6 +33,6 @@ class MockBuildDependencyGenerator : public ClangBackEnd::BuildDependencyGenerat { public: MOCK_METHOD1(create, - ClangBackEnd::BuildDependency (const ClangBackEnd::V2::ProjectPartContainer &projectPart)); + ClangBackEnd::BuildDependency (const ClangBackEnd::ProjectPartContainer &projectPart)); }; diff --git a/tests/unit/unittest/mockpchcreator.h b/tests/unit/unittest/mockpchcreator.h index 992976d4de..86a34ac04f 100644 --- a/tests/unit/unittest/mockpchcreator.h +++ b/tests/unit/unittest/mockpchcreator.h @@ -30,18 +30,21 @@ #include <filecontainerv2.h> #include <pchcreatorinterface.h> #include <projectpartpch.h> -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> class MockPchCreator : public ClangBackEnd::PchCreatorInterface { public: - MOCK_METHOD1(generatePchDeprecated, void(const ClangBackEnd::V2::ProjectPartContainer &projectPart)); MOCK_METHOD1(generatePch, void(const ClangBackEnd::PchTask &pchTask)); - 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 generatePch(ClangBackEnd::PchTask &&pchTask) override + { + generatePch(pchTask); + } }; diff --git a/tests/unit/unittest/mockpchtaskgenerator.h b/tests/unit/unittest/mockpchtaskgenerator.h new file mode 100644 index 0000000000..4934d7a9a6 --- /dev/null +++ b/tests/unit/unittest/mockpchtaskgenerator.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 <pchtaskgeneratorinterface.h> + +class MockPchTaskGenerator : public ClangBackEnd::PchTaskGeneratorInterface +{ +public: + MOCK_METHOD2(addProjectParts, + void(const ClangBackEnd::ProjectPartContainers &projectParts, + const Utils::SmallStringVector &toolChainArguments)); + MOCK_METHOD1(removeProjectParts, + void (const Utils::SmallStringVector &projectsPartIds)); + + void addProjectParts(ClangBackEnd::ProjectPartContainers &&projectParts, + Utils::SmallStringVector &&toolChainArguments) override + { + addProjectParts(projectParts, toolChainArguments); + } +}; diff --git a/tests/unit/unittest/mockpchtasksmerger.h b/tests/unit/unittest/mockpchtasksmerger.h index c320159d34..39e73f9f55 100644 --- a/tests/unit/unittest/mockpchtasksmerger.h +++ b/tests/unit/unittest/mockpchtasksmerger.h @@ -32,7 +32,15 @@ class MockPchTasksMerger : public ClangBackEnd::PchTasksMergerInterface { public: - MOCK_METHOD1(mergeTasks, void(const ClangBackEnd::PchTaskSets &pchTaskSets)); + MOCK_METHOD2(mergeTasks, + void(const ClangBackEnd::PchTaskSets &pchTaskSets, + const Utils::SmallStringVector &toolChainArguments)); - void mergeTasks(ClangBackEnd::PchTaskSets &&pchTaskSets) override { mergeTasks(pchTaskSets); } + MOCK_METHOD1(removePchTasks, void(const Utils::SmallStringVector &projectPartIds)); + + void mergeTasks(ClangBackEnd::PchTaskSets &&pchTaskSets, + Utils::SmallStringVector &&toolChainArguments) override + { + mergeTasks(pchTaskSets, toolChainArguments); + } }; diff --git a/tests/unit/unittest/mockprecompiledheaderstorage.h b/tests/unit/unittest/mockprecompiledheaderstorage.h index c267ecb535..a2bc0fddf0 100644 --- a/tests/unit/unittest/mockprecompiledheaderstorage.h +++ b/tests/unit/unittest/mockprecompiledheaderstorage.h @@ -37,11 +37,12 @@ public: Utils::SmallStringView pchPath, long long pchBuildTime)); MOCK_METHOD1(deleteProjectPrecompiledHeader, void(Utils::SmallStringView projectPartName)); - MOCK_METHOD3(insertSystemPrecompiledHeader, - void(Utils::SmallStringView projectPartName, + MOCK_METHOD3(insertSystemPrecompiledHeaders, + void(const Utils::SmallStringVector &projectPartNames, Utils::SmallStringView pchPath, long long pchBuildTime)); - MOCK_METHOD1(deleteSystemPrecompiledHeader, void(Utils::SmallStringView projectPartName)); + MOCK_METHOD1(deleteSystemPrecompiledHeaders, + void(const Utils::SmallStringVector &projectPartNames)); MOCK_METHOD1(fetchSystemPrecompiledHeaderPath, - Utils::PathString(Utils::SmallStringView projectPartName)); + ClangBackEnd::FilePath(Utils::SmallStringView projectPartName)); }; diff --git a/tests/unit/unittest/mockprojectpartqueue.h b/tests/unit/unittest/mockprojectpartqueue.h index 8d1ec1f66c..022878c73a 100644 --- a/tests/unit/unittest/mockprojectpartqueue.h +++ b/tests/unit/unittest/mockprojectpartqueue.h @@ -33,13 +33,13 @@ class MockProjectPartQueue : public ClangBackEnd::ProjectPartQueueInterface { public: MOCK_METHOD1(addProjectParts, - void (const ClangBackEnd::V2::ProjectPartContainers &projectParts)); + void (const ClangBackEnd::ProjectPartContainers &projectParts)); MOCK_METHOD1(removeProjectParts, void (const Utils::SmallStringVector &projectsPartIds)); MOCK_METHOD0(processEntries, void ()); - void addProjectParts(ClangBackEnd::V2::ProjectPartContainers &&projectParts) override + void addProjectParts(ClangBackEnd::ProjectPartContainers &&projectParts) override { addProjectParts(projectParts); } diff --git a/tests/unit/unittest/mockprojectparts.h b/tests/unit/unittest/mockprojectparts.h index 611e12b9fe..f81eabc91c 100644 --- a/tests/unit/unittest/mockprojectparts.h +++ b/tests/unit/unittest/mockprojectparts.h @@ -33,13 +33,13 @@ class MockProjectParts : public ClangBackEnd::ProjectPartsInterface { public: MOCK_METHOD1(update, - ClangBackEnd::V2::ProjectPartContainers(const ClangBackEnd::V2::ProjectPartContainers &projectsParts)); + ClangBackEnd::ProjectPartContainers(const ClangBackEnd::ProjectPartContainers &projectsParts)); MOCK_METHOD1(remove, void(const Utils::SmallStringVector &projectPartIds)); MOCK_CONST_METHOD1(projects, - ClangBackEnd::V2::ProjectPartContainers(const Utils::SmallStringVector &projectPartIds)); + ClangBackEnd::ProjectPartContainers(const Utils::SmallStringVector &projectPartIds)); - ClangBackEnd::V2::ProjectPartContainers update(ClangBackEnd::V2::ProjectPartContainers &&projectsParts) override + ClangBackEnd::ProjectPartContainers update(ClangBackEnd::ProjectPartContainers &&projectsParts) override { return update(projectsParts); } diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp index 128b3d899f..79fb9879b7 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ b/tests/unit/unittest/mocksqlitereadstatement.cpp @@ -145,15 +145,22 @@ MockSqliteReadStatement::value<Utils::PathString>(const Utils::SmallStringView & } template <> +Utils::optional<ClangBackEnd::FilePath> +MockSqliteReadStatement::value<ClangBackEnd::FilePath>(const Utils::SmallStringView &path) +{ + return valueReturnFilePath(path); +} + +template <> Utils::optional<ClangBackEnd::ProjectPartArtefact> -MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int& sourceId) +MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 5>(const int& sourceId) { return valueReturnProjectPartArtefact(sourceId); } template <> Utils::optional<ClangBackEnd::ProjectPartArtefact> -MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const Utils::SmallStringView &projectPartName) +MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 5>(const Utils::SmallStringView &projectPartName) { return valueReturnProjectPartArtefact(projectPartName); } diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index 4fbdda2a6d..a5c15e46b7 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -99,6 +99,9 @@ public: MOCK_METHOD1(valueReturnPathString, Utils::optional<Utils::PathString>(Utils::SmallStringView)); + MOCK_METHOD1(valueReturnFilePath, + Utils::optional<ClangBackEnd::FilePath>(Utils::SmallStringView)); + MOCK_METHOD1(valueReturnSmallString, Utils::optional<Utils::SmallString>(int)); @@ -213,6 +216,10 @@ Utils::optional<int> MockSqliteReadStatement::value<int>(const Utils::PathString&); template <> +Utils::optional<ClangBackEnd::FilePath> +MockSqliteReadStatement::value<ClangBackEnd::FilePath>(const Utils::SmallStringView&); + +template <> Utils::optional<int> MockSqliteReadStatement::value<int>(const int&, const Utils::SmallStringView&); @@ -230,11 +237,11 @@ MockSqliteReadStatement::value<Utils::PathString>(const Utils::SmallStringView&) template <> Utils::optional<ClangBackEnd::ProjectPartArtefact> -MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int&); +MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 5>(const int&); template <> Utils::optional<ClangBackEnd::ProjectPartArtefact> -MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 4>(const int&); +MockSqliteReadStatement::value<ClangBackEnd::ProjectPartArtefact, 5>(const int&); template <> Utils::optional<ClangBackEnd::ProjectPartPch> diff --git a/tests/unit/unittest/mocksqlitewritestatement.h b/tests/unit/unittest/mocksqlitewritestatement.h index 8da4db8ef5..7e2cb0270a 100644 --- a/tests/unit/unittest/mocksqlitewritestatement.h +++ b/tests/unit/unittest/mocksqlitewritestatement.h @@ -78,6 +78,12 @@ public: Utils::SmallStringView, Utils::SmallStringView)); + MOCK_METHOD5(write, + void (Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView, + Utils::SmallStringView)); MOCK_METHOD1(write, void (Utils::SmallStringView)); diff --git a/tests/unit/unittest/mocksymbolindexing.h b/tests/unit/unittest/mocksymbolindexing.h index 048840d976..c502f62d77 100644 --- a/tests/unit/unittest/mocksymbolindexing.h +++ b/tests/unit/unittest/mocksymbolindexing.h @@ -33,9 +33,9 @@ class MockSymbolIndexing : public ClangBackEnd::SymbolIndexingInterface { public: MOCK_METHOD1(updateProjectParts, - void(const ClangBackEnd::V2::ProjectPartContainers &projectParts)); + void(const ClangBackEnd::ProjectPartContainers &projectParts)); - void updateProjectParts(ClangBackEnd::V2::ProjectPartContainers &&projectParts) override + void updateProjectParts(ClangBackEnd::ProjectPartContainers &&projectParts) override { updateProjectParts(projectParts); } diff --git a/tests/unit/unittest/mocksymbolstorage.h b/tests/unit/unittest/mocksymbolstorage.h index c9de142bd4..5b2451bf5a 100644 --- a/tests/unit/unittest/mocksymbolstorage.h +++ b/tests/unit/unittest/mocksymbolstorage.h @@ -37,11 +37,12 @@ public: MOCK_METHOD2(addSymbolsAndSourceLocations, void(const ClangBackEnd::SymbolEntries &symbolEentries, const ClangBackEnd::SourceLocationEntries &sourceLocations)); - MOCK_METHOD4(insertOrUpdateProjectPart, + MOCK_METHOD5(insertOrUpdateProjectPart, int(Utils::SmallStringView projectPartName, const Utils::SmallStringVector &commandLineArgument, const ClangBackEnd::CompilerMacros &compilerMacros, - const Utils::SmallStringVector &includeSearchPaths)); + const ClangBackEnd::IncludeSearchPaths &systemIncludeSearchPaths, + const ClangBackEnd::IncludeSearchPaths &projectIncludeSearchPaths)); MOCK_METHOD2(updateProjectPartSources, void(int projectPartId, const ClangBackEnd::FilePathIds &sourceFilePathIds)); diff --git a/tests/unit/unittest/modifiedtimechecker-test.cpp b/tests/unit/unittest/modifiedtimechecker-test.cpp new file mode 100644 index 0000000000..8e0c881b38 --- /dev/null +++ b/tests/unit/unittest/modifiedtimechecker-test.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** 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 <filepathcaching.h> +#include <modifiedtimechecker.h> +#include <refactoringdatabaseinitializer.h> + +namespace { + +using ClangBackEnd::SourceEntries; +using ClangBackEnd::SourceType; +using ClangBackEnd::FilePathView; + + +class ModifiedTimeChecker : public testing::Test +{ +protected: + + ClangBackEnd::FilePathId id(const Utils::SmallStringView &path) const + { + return filePathCache.filePathId(ClangBackEnd::FilePathView{path}); + } + + + ModifiedTimeChecker() + { + ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1")))).WillByDefault(Return(50)); + ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2")))).WillByDefault(Return(30)); + } + NiceMock<MockFunction<ClangBackEnd::TimeStamp(ClangBackEnd::FilePathView filePath)>> getModifiedTimeCallback; + Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; + ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database}; + ClangBackEnd::FilePathCaching filePathCache{database}; + decltype(getModifiedTimeCallback.AsStdFunction()) callback = getModifiedTimeCallback + .AsStdFunction(); + ClangBackEnd::ModifiedTimeChecker checker{callback, filePathCache}; + SourceEntries upToDateEntries = {{id("/path1"), SourceType::UserInclude, 100}, + {id("/path2"), SourceType::SystemInclude, 30}}; + SourceEntries notUpToDateEntries = {{id("/path1"), SourceType::UserInclude, 50}, + {id("/path2"), SourceType::SystemInclude, 20}}; +}; + +TEST_F(ModifiedTimeChecker, IsUpToDate) +{ + auto isUpToDate = checker.isUpToDate(upToDateEntries); + + ASSERT_TRUE(isUpToDate); +} + +TEST_F(ModifiedTimeChecker, IsNotUpToDateIfSourceEntriesAreEmpty) +{ + auto isUpToDate = checker.isUpToDate({}); + + ASSERT_FALSE(isUpToDate); +} + +TEST_F(ModifiedTimeChecker, IsNotUpToDate) +{ + auto isUpToDate = checker.isUpToDate({}); + + ASSERT_FALSE(isUpToDate); +} + +TEST_F(ModifiedTimeChecker, PathChangesUpdatesTimeStamps) +{ + checker.isUpToDate(upToDateEntries); + + EXPECT_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1")))); + EXPECT_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2")))); + + checker.pathsChanged({id(FilePathView("/path1")), id(FilePathView("/path2")), id(FilePathView("/path3"))}); +} + +TEST_F(ModifiedTimeChecker, IsNotUpToDateAnyMoreAfterUpdating) +{ + checker.isUpToDate(upToDateEntries); + ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1")))).WillByDefault(Return(120)); + ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2")))).WillByDefault(Return(30)); + + checker.pathsChanged({id(FilePathView("/path1")), id(FilePathView("/path2")), id(FilePathView("/path3"))}); + + ASSERT_FALSE(checker.isUpToDate(upToDateEntries)); +} + +} // namespace diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index 8b556af6b7..68c67ecdd5 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -50,22 +50,25 @@ using ClangBackEnd::FilePathIds; using ClangBackEnd::FilePathView; using ClangBackEnd::GeneratedFiles; using ClangBackEnd::IdPaths; +using ClangBackEnd::IncludeSearchPathType; +using ClangBackEnd::PchTask; using ClangBackEnd::ProjectPartPch; using ClangBackEnd::SourceEntries; using ClangBackEnd::SourceEntry; using ClangBackEnd::SourceType; using ClangBackEnd::V2::FileContainer; -using ClangBackEnd::V2::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainer; using Utils::PathString; using Utils::SmallString; using UnitTests::EndsWith; -MATCHER_P2(HasIdAndType, sourceId, sourceType, - std::string(negation ? "hasn't" : "has") + - PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType, - -1))) +MATCHER_P2(HasIdAndType, + sourceId, + sourceType, + std::string(negation ? "hasn't" : "has") + + PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType, -1))) { const ClangBackEnd::SourceEntry &entry = arg; return entry.sourceId == sourceId && entry.sourceType == sourceType; @@ -74,7 +77,7 @@ MATCHER_P2(HasIdAndType, sourceId, sourceType, class PchCreator: public ::testing::Test { protected: - void SetUp() + PchCreator() { creator.setUnsavedFiles({generatedFile}); } @@ -96,86 +99,26 @@ protected: TestEnvironment environment; FileContainer generatedFile{{TESTDATA_DIR, generatedFileName}, "#pragma once", {}}; NiceMock<MockPchManagerClient> mockPchManagerClient; - NiceMock<MockClangPathWatcher> mockClangPathWatcher; - ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient, mockClangPathWatcher}; - ProjectPartContainer projectPart1{"project1", - {"-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system", "-Wno-pragma-once-outside-header"}, - {{"DEFINE", "1", 1}}, - {TESTDATA_DIR "/builddependencycollector/external", TESTDATA_DIR "/builddependencycollector/project"}, - {id(header1Path)}, - {id(main1Path)}}; - ProjectPartContainer projectPart2{"project2", - {"-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-x", "c++-header", "-Wno-pragma-once-outside-header"}, - {{"DEFINE", "1", 1}}, - {TESTDATA_DIR "/builddependencycollector/external", TESTDATA_DIR "/builddependencycollector/project"}, - {id(header2Path)}, - {id(main2Path)}}; + ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient}; + PchTask pchTask1{ + "project1", + {id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external2.h")}, + {}, + {}, + {}, + {{TESTDATA_DIR "/builddependencycollector/system", 2, IncludeSearchPathType::BuiltIn}, + {TESTDATA_DIR "/builddependencycollector/external", 1, IncludeSearchPathType::System}}, + {{TESTDATA_DIR "/builddependencycollector/project", 1, IncludeSearchPathType::User}}, + }; }; using PchCreatorSlowTest = PchCreator; using PchCreatorVerySlowTest = PchCreator; -TEST_F(PchCreator, ConvertToQStringList) +TEST_F(PchCreator, CreateProjectPartPchFileContent) { - auto arguments = creator.convertToQStringList({"-I", TESTDATA_DIR}); - - ASSERT_THAT(arguments, ElementsAre(QString("-I"), QString(TESTDATA_DIR))); -} - -TEST_F(PchCreator, CreateProjectPartCommandLine) -{ - auto commandLine = creator.generateProjectPartCommandLine(projectPart1); - - ASSERT_THAT(commandLine, ElementsAre(environment.clangCompilerPath(), "-I", TESTDATA_DIR, "-I", TESTDATA_DIR "/builddependencycollector/external", "-I", TESTDATA_DIR "/builddependencycollector/project", "-isystem", TESTDATA_DIR "/builddependencycollector/system", "-Wno-pragma-once-outside-header")); -} - -TEST_F(PchCreator, CreateProjectPartHeaders) -{ - auto includeIds = creator.generateProjectPartHeaders(projectPart1); - - ASSERT_THAT(includeIds, UnorderedElementsAre(header1Path, generatedFilePath)); -} - -TEST_F(PchCreator, CreateProjectPartSources) -{ - auto includeIds = creator.generateProjectPartSourcePaths(projectPart1); - - ASSERT_THAT(includeIds, UnorderedElementsAre(main1Path)); -} - -TEST_F(PchCreatorSlowTest, CreateProjectPartPchIncludes) -{ - using ClangBackEnd::PchCreatorIncludes; - - auto includeIds = creator.generateProjectPartPchIncludes(projectPart1); - - ASSERT_THAT( - includeIds, - AllOf( - Contains(HasIdAndType( - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), - SourceType::TopProjectInclude)), - Contains(HasIdAndType( - id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), - SourceType::TopSystemInclude)), - Contains(HasIdAndType( - id(TESTDATA_DIR - "/builddependencycollector/system/indirect_system.h"), - SourceType::SystemInclude)), - Contains(HasIdAndType( - id(TESTDATA_DIR - "/builddependencycollector/external/external1.h"), - SourceType::TopProjectInclude)), - Contains(HasIdAndType( - id(TESTDATA_DIR - "/builddependencycollector/external/external2.h"), - SourceType::TopProjectInclude)))); -} - -TEST_F(PchCreatorSlowTest, CreateProjectPartPchFileContent) -{ - auto includes = creator.generateProjectPartPchIncludes(projectPart1); - - auto content = creator.generatePchIncludeFileContent(creator.topIncludeIds(includes)); + auto content = creator.generatePchIncludeFileContent(pchTask1.includes); ASSERT_THAT(std::string(content), AllOf(HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/project/header2.h\"\n"), @@ -183,11 +126,10 @@ TEST_F(PchCreatorSlowTest, CreateProjectPartPchFileContent) HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/external/external2.h\"\n"))); } -TEST_F(PchCreatorSlowTest, CreateProjectPartPchIncludeFile) +TEST_F(PchCreator, CreatePchIncludeFile) { - auto includes = creator.generateProjectPartPchIncludes(projectPart1); - auto content = creator.generatePchIncludeFileContent(creator.topIncludeIds(includes)); - auto pchIncludeFilePath = creator.generateProjectPathPchHeaderFilePath(projectPart1); + auto content = creator.generatePchIncludeFileContent(pchTask1.includes); + auto pchIncludeFilePath = creator.generatePchHeaderFilePath(); auto file = creator.generateFileWithContent(pchIncludeFilePath, content); file->open(QIODevice::ReadOnly); @@ -199,38 +141,63 @@ TEST_F(PchCreatorSlowTest, CreateProjectPartPchIncludeFile) HasSubstr("#include \"" TESTDATA_DIR "/builddependencycollector/external/external2.h\"\n"))); } -TEST_F(PchCreator, CreateProjectPartPchCompilerArguments) -{ - auto arguments = creator.generateProjectPartPchCompilerArguments(projectPart1); - - ASSERT_THAT(arguments, AllOf(Contains("-x"), - Contains("c++-header"), - Contains("-Xclang"), - Contains("-emit-pch"), - Contains("-o"), - Contains(EndsWith(".pch")))); -} - TEST_F(PchCreator, CreateProjectPartClangCompilerArguments) { - auto arguments = creator.generateProjectPartClangCompilerArguments(projectPart1); - - ASSERT_THAT(arguments, AllOf(Contains(TESTDATA_DIR), - Contains("-emit-pch"), - Contains("-o"), - Not(Contains(environment.clangCompilerPath())))); -} - -TEST_F(PchCreatorVerySlowTest, IncludesForCreatePchsForProjectParts) -{ - creator.generatePchDeprecated(projectPart1); - - ASSERT_THAT(creator.takeProjectIncludes().id, "project1"); + auto arguments = creator.generateClangCompilerArguments(std::move(pchTask1), + "project.h", + "project.pch"); + + ASSERT_THAT(arguments, + ElementsAre("clang++", + "-x", + "c++-header", + "-std=c++98", + "-nostdinc", + "-nostdlibinc", + "-I", + TESTDATA_DIR "/builddependencycollector/project", + "-isystem", + TESTDATA_DIR "/builddependencycollector/external", + "-isystem", + TESTDATA_DIR "/builddependencycollector/system", + "-o", + "project.pch", + "project.h")); +} + +TEST_F(PchCreator, CreateProjectPartClangCompilerArgumentsWithSystemPch) +{ + pchTask1.systemPchPath = "system.pch"; + + auto arguments = creator.generateClangCompilerArguments(std::move(pchTask1), + "project.h", + "project.pch"); + + ASSERT_THAT(arguments, + ElementsAre("clang++", + "-x", + "c++-header", + "-std=c++98", + "-nostdinc", + "-nostdlibinc", + "-I", + TESTDATA_DIR "/builddependencycollector/project", + "-isystem", + TESTDATA_DIR "/builddependencycollector/external", + "-isystem", + TESTDATA_DIR "/builddependencycollector/system", + "-Xclang", + "-include-pch", + "-Xclang", + "system.pch", + "-o", + "project.pch", + "project.h")); } TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient) { - creator.generatePchDeprecated(projectPart1); + creator.generatePch(std::move(pchTask1)); EXPECT_CALL(mockPchManagerClient, precompiledHeadersUpdated( @@ -240,30 +207,10 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient) creator.doInMainThreadAfterFinished(); } -TEST_F(PchCreatorVerySlowTest, UpdateFileWatcherIncludes) -{ - creator.generatePchDeprecated(projectPart1); - - EXPECT_CALL(mockClangPathWatcher, - updateIdPaths(ElementsAre(creator.projectIncludes()))); - - creator.doInMainThreadAfterFinished(); -} -TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts) +TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForPchTask) { - creator.generatePchDeprecated(projectPart1); - - ASSERT_THAT(creator.takeProjectIncludes(), - AllOf(Field(&IdPaths::id, "project1"), - Field(&IdPaths::filePathIds, AllOf(Contains(id(TESTDATA_DIR "/builddependencycollector/project/header2.h")), - Contains(id(TESTDATA_DIR "/builddependencycollector/external/external1.h")), - Contains(id(TESTDATA_DIR "/builddependencycollector/external/external2.h")))))); -} - -TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart) -{ - creator.generatePchDeprecated(projectPart1); + creator.generatePch(std::move(pchTask1)); ASSERT_THAT(creator.projectPartPch(), AllOf(Field(&ProjectPartPch::projectPartId, Eq("project1")), @@ -273,52 +220,29 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForProjectPart) TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared) { - creator.generatePchDeprecated(projectPart1); + creator.generatePch(std::move(pchTask1)); creator.clear(); ASSERT_THAT(creator.projectPartPch(), ClangBackEnd::ProjectPartPch{}); } - -TEST_F(PchCreatorVerySlowTest, ProjectIncludesCleared) -{ - creator.generatePchDeprecated(projectPart1); - - creator.clear(); - - ASSERT_THAT(creator.projectIncludes(), ClangBackEnd::IdPaths{}); -} - -TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesNoPchForProjectPart) +TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesFaultyPchForPchTask) { - ProjectPartContainer faultyProjectPart{"faultyProject", - {"-I", TESTDATA_DIR}, - {{"DEFINE", "1", 1}}, - {"/includes"}, - {}, - {id(TESTDATA_DIR "/builddependencycollector/project/faulty.cpp")}}; + PchTask faultyPchTask{"faultyProjectPart", + {id(TESTDATA_DIR "/builddependencycollector/project/faulty.cpp")}, + {{"DEFINE", "1", 1}}, + {}, + {}, + {{TESTDATA_DIR "/builddependencycollector/external", 1, IncludeSearchPathType::System}}, + {{TESTDATA_DIR "/builddependencycollector/project", 1, IncludeSearchPathType::User}}}; - creator.generatePchDeprecated(faultyProjectPart); + creator.generatePch(std::move(faultyPchTask)); ASSERT_THAT(creator.projectPartPch(), - AllOf(Field(&ProjectPartPch::projectPartId, Eq("faultyProject")), + AllOf(Field(&ProjectPartPch::projectPartId, Eq("faultyProjectPart")), Field(&ProjectPartPch::pchPath, IsEmpty()), Field(&ProjectPartPch::lastModified, Eq(-1)))); } -TEST_F(PchCreator, CreateProjectPartSourcesContent) -{ - auto content = creator.generateProjectPartSourcesContent(projectPart1); - - ASSERT_THAT(content, Eq("#include \"" TESTDATA_DIR "/builddependencycollector/project/main3.cpp\"\n")); -} - -TEST_F(PchCreator, Call) -{ - auto content = creator.generateProjectPartSourcesContent(projectPart1); - - ASSERT_THAT(content, Eq("#include \"" TESTDATA_DIR "/builddependencycollector/project/main3.cpp\"\n")); -} - } diff --git a/tests/unit/unittest/pchmanagerclient-test.cpp b/tests/unit/unittest/pchmanagerclient-test.cpp index cec39fc73e..d35e595b04 100644 --- a/tests/unit/unittest/pchmanagerclient-test.cpp +++ b/tests/unit/unittest/pchmanagerclient-test.cpp @@ -62,10 +62,10 @@ protected: ClangBackEnd::FilePathCaching filePathCache{database}; ClangPchManager::PchManagerProjectUpdater projectUpdater{mockPchManagerServer, client, filePathCache}; Utils::SmallString projectPartId{"projectPartId"}; - Utils::SmallString pchFilePath{"/path/to/pch"}; + ClangBackEnd::FilePath pchFilePath{"/path/to/pch"}; PrecompiledHeadersUpdatedMessage message{{{projectPartId.clone(), pchFilePath.clone(), 1}}}; Utils::SmallString projectPartId2{"projectPartId2"}; - Utils::SmallString pchFilePath2{"/path/to/pch2"}; + ClangBackEnd::FilePath pchFilePath2{"/path/to/pch2"}; PrecompiledHeadersUpdatedMessage message2{{{projectPartId2.clone(), pchFilePath2.clone(), 1}}}; }; diff --git a/tests/unit/unittest/pchmanagerclientserverinprocess-test.cpp b/tests/unit/unittest/pchmanagerclientserverinprocess-test.cpp index 13a4ad3437..a16b3981e4 100644 --- a/tests/unit/unittest/pchmanagerclientserverinprocess-test.cpp +++ b/tests/unit/unittest/pchmanagerclientserverinprocess-test.cpp @@ -49,7 +49,7 @@ using ClangBackEnd::UpdateProjectPartsMessage; using ClangBackEnd::RemoveGeneratedFilesMessage; using ClangBackEnd::RemoveProjectPartsMessage; using ClangBackEnd::V2::FileContainer; -using ClangBackEnd::V2::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainer; using ClangBackEnd::PrecompiledHeadersUpdatedMessage; using ::testing::Args; @@ -97,13 +97,18 @@ TEST_F(PchManagerClientServerInProcess, SendAliveMessage) TEST_F(PchManagerClientServerInProcess, SendUpdateProjectPartsMessage) { - ProjectPartContainer projectPart2{"projectPartId", - {"-x", "c++-header", "-Wno-pragma-once-outside-header"}, - {{"DEFINE", "1", 1}}, - {"/includes"}, - {{1, 1}}, - {{1, 2}}}; - UpdateProjectPartsMessage message{{projectPart2}}; + ProjectPartContainer projectPart2{ + "projectPartId", + {"-x", "c++-header", "-Wno-pragma-once-outside-header"}, + {{"DEFINE", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {{1, 1}}, + {{1, 2}}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; + UpdateProjectPartsMessage message{{projectPart2}, {"-m32"}}; EXPECT_CALL(mockPchManagerServer, updateProjectParts(message)); diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp index 77106268d1..9aab088b33 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 "mockprojectpartqueue.h" +#include "mockpchtaskgenerator.h" #include "mockprojectparts.h" #include "mockgeneratedfiles.h" @@ -46,7 +46,7 @@ using Utils::PathString; using Utils::SmallString; using ClangBackEnd::V2::FileContainer; using ClangBackEnd::V2::FileContainers; -using ClangBackEnd::V2::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainer; class PchManagerServer : public ::testing::Test { @@ -64,14 +64,15 @@ class PchManagerServer : public ::testing::Test } protected: - NiceMock<MockProjectPartQueue> mockProjectPartQueue; + NiceMock<MockPchTaskGenerator> mockPchTaskGenerator; NiceMock<MockClangPathWatcher> mockClangPathWatcher; NiceMock<MockProjectParts> mockProjectParts; NiceMock<MockGeneratedFiles> mockGeneratedFiles; Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; - ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockProjectPartQueue, mockProjectParts, mockGeneratedFiles}; + ClangBackEnd::PchManagerServer server{ + mockClangPathWatcher, mockPchTaskGenerator, mockProjectParts, mockGeneratedFiles}; NiceMock<MockPchManagerClient> mockPchManagerClient; SmallString projectPartId1 = "project1"; SmallString projectPartId2 = "project2"; @@ -80,22 +81,33 @@ protected: PathString header1Path = TESTDATA_DIR "/BuildDependencyCollector_header1.h"; PathString header2Path = TESTDATA_DIR "/BuildDependencyCollector_header2.h"; ClangBackEnd::IdPaths idPath{projectPartId1, {1, 2}}; - ProjectPartContainer projectPart1{projectPartId1.clone(), - {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, - {{"DEFINE", "1", 1}}, - {"/includes"}, - {id(header1Path)}, - {id(main1Path)}}; - ProjectPartContainer projectPart2{projectPartId2.clone(), - {"-x", "c++-header", "-Wno-pragma-once-outside-header"}, - {{"DEFINE", "1", 1}}, - {"/includes"}, - {id(header2Path)}, - {id(main2Path)}}; + ProjectPartContainer projectPart1{ + projectPartId1.clone(), + {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, + {{"DEFINE", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {id(header1Path)}, + {id(main1Path)}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; + ProjectPartContainer projectPart2{ + projectPartId2.clone(), + {"-x", "c++-header", "-Wno-pragma-once-outside-header"}, + {{"DEFINE", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {id(header2Path)}, + {id(main2Path)}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; std::vector<ProjectPartContainer> projectParts{projectPart1, projectPart2}; std::vector<ProjectPartContainer> projectParts2{projectPart2}; FileContainer generatedFile{{"/path/to/", "file"}, "content", {}}; - ClangBackEnd::UpdateProjectPartsMessage updateProjectPartsMessage{Utils::clone(projectParts)}; + ClangBackEnd::UpdateProjectPartsMessage updateProjectPartsMessage{ + Utils::clone(projectParts), {"toolChainArgument"}}; ClangBackEnd::RemoveProjectPartsMessage removeProjectPartsMessage{{projectPart1.projectPartId.clone(), projectPart2.projectPartId.clone()}}; }; @@ -104,8 +116,10 @@ TEST_F(PchManagerServer, FilterProjectPartsAndSendThemToQueue) { InSequence s; - EXPECT_CALL(mockProjectParts, update(updateProjectPartsMessage.projectsParts)).WillOnce(Return(projectParts2)); - EXPECT_CALL(mockProjectPartQueue, addProjectParts(Eq(projectParts2))); + EXPECT_CALL(mockProjectParts, update(updateProjectPartsMessage.projectsParts)) + .WillOnce(Return(projectParts2)); + EXPECT_CALL( + mockPchTaskGenerator, addProjectParts(Eq(projectParts2), ElementsAre("toolChainArgument"))); server.updateProjectParts(updateProjectPartsMessage.clone()); } @@ -146,14 +160,17 @@ TEST_F(PchManagerServer, SetPathWatcherNotifier) { EXPECT_CALL(mockClangPathWatcher, setNotifier(_)); - ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockProjectPartQueue, mockProjectParts, mockGeneratedFiles}; + ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockPchTaskGenerator, mockProjectParts, mockGeneratedFiles}; } TEST_F(PchManagerServer, UpdateProjectPartQueueByPathIds) { + server.updateProjectParts( + ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); + EXPECT_CALL(mockProjectParts, projects(ElementsAre(projectPart1.projectPartId))) - .WillOnce(Return(std::vector<ClangBackEnd::V2::ProjectPartContainer>{{projectPart1}})); - EXPECT_CALL(mockProjectPartQueue, addProjectParts(ElementsAre(projectPart1))); + .WillOnce(Return(std::vector<ClangBackEnd::ProjectPartContainer>{{projectPart1}})); + EXPECT_CALL(mockPchTaskGenerator, addProjectParts(ElementsAre(projectPart1), ElementsAre("toolChainArgument"))); server.pathsWithIdsChanged({projectPartId1}); } @@ -166,4 +183,17 @@ TEST_F(PchManagerServer, SetProgress) server.setProgress(20, 30); } + +TEST_F(PchManagerServer, RemoveToolChainsArguments) +{ + server.updateProjectParts( + ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); + + EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); + server.removeProjectParts(removeProjectPartsMessage.clone()); + + server.pathsWithIdsChanged({projectPart1.projectPartId}); +} + + } diff --git a/tests/unit/unittest/pchtaskgenerator-test.cpp b/tests/unit/unittest/pchtaskgenerator-test.cpp index 0cb4c93583..74610f5170 100644 --- a/tests/unit/unittest/pchtaskgenerator-test.cpp +++ b/tests/unit/unittest/pchtaskgenerator-test.cpp @@ -32,10 +32,12 @@ namespace { -using ClangBackEnd::BuildDependency; using ClangBackEnd::BuildDependencies; +using ClangBackEnd::BuildDependency; using ClangBackEnd::CompilerMacro; using ClangBackEnd::FilePathId; +using ClangBackEnd::IncludeSearchPath; +using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::PchTask; using ClangBackEnd::PchTaskSet; using ClangBackEnd::SourceEntries; @@ -49,21 +51,29 @@ protected: NiceMock<MockBuildDependenciesProvider> mockBuildDependenciesProvider; NiceMock<MockPchTasksMerger> mockPchTaskMerger; ClangBackEnd::PchTaskGenerator generator{mockBuildDependenciesProvider, mockPchTaskMerger}; - ClangBackEnd::V2::ProjectPartContainer projectPart1{"ProjectPart1", - {"--yi"}, - {{"YI", "1", 1}, - {"QI", "7", 1}, - {"ER", "2", 2}, - {"SAN", "3", 3}, - {"SE", "4", 4}, - {"BA", "8", 4}, - {"WU", "5", 5}, - {"LUI", "6", 6}, - {"JIU", "9", 9}, - {"SHI", "10", 10}}, - {"/yi"}, - {{1, 1}}, - {{1, 2}}}; + ClangBackEnd::ProjectPartContainer projectPart1{ + "ProjectPart1", + {"--yi"}, + {{"YI", "1", 1}, + {"QI", "7", 1}, + {"ER", "2", 2}, + {"SAN", "3", 3}, + {"SE", "4", 4}, + {"BA", "8", 4}, + {"WU", "5", 5}, + {"LUI", "6", 6}, + {"JIU", "9", 9}, + {"SHI", "10", 10}}, + {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, + IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, + IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, + {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, + IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}, + {{1, 1}}, + {{1, 2}}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX11, + Utils::LanguageExtension::All}; SourceEntries firstSources{{1, SourceType::ProjectInclude, 1}, {2, SourceType::UserInclude, 1}, {3, SourceType::TopProjectInclude, 1}, @@ -73,32 +83,68 @@ protected: BuildDependency buildDependency{firstSources, usedMacros, {}, {}, {}}; }; -TEST_F(PchTaskGenerator, Create) +TEST_F(PchTaskGenerator, AddProjectParts) +{ + ON_CALL(mockBuildDependenciesProvider, create(_)).WillByDefault(Return(buildDependency)); + + EXPECT_CALL( + mockPchTaskMerger, + mergeTasks( + ElementsAre(AllOf( + Field( + &PchTaskSet::system, + AllOf( + Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")), + Field(&PchTask::includes, ElementsAre(5)), + Field(&PchTask::compilerMacros, + ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})), + Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})), + Field(&PchTask::systemIncludeSearchPaths, + ElementsAre( + IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, + IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, + IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System})), + Field(&PchTask::projectIncludeSearchPaths, + ElementsAre(IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, + IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User})), + Field(&PchTask::toolChainArguments, ElementsAre("--yi")), + Field(&PchTask::language, Eq(Utils::Language::Cxx)), + Field(&PchTask::languageVersion, Eq(Utils::LanguageVersion::CXX11)), + Field(&PchTask::languageExtension, Eq(Utils::LanguageExtension::All)))), + AllOf(Field( + &PchTaskSet::project, + AllOf( + Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")), + Field(&PchTask::includes, ElementsAre(3)), + Field(&PchTask::compilerMacros, + ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})), + Field(&PchTask::usedMacros, ElementsAre(UsedMacro{"YI", 1}, UsedMacro{"SAN", 3})), + Field(&PchTask::systemIncludeSearchPaths, + ElementsAre( + IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, + IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, + IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System})), + Field(&PchTask::projectIncludeSearchPaths, + ElementsAre(IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, + IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User})), + Field(&PchTask::toolChainArguments, ElementsAre("--yi")), + Field(&PchTask::language, Eq(Utils::Language::Cxx)), + Field(&PchTask::languageVersion, Eq(Utils::LanguageVersion::CXX11)), + Field(&PchTask::languageExtension, Eq(Utils::LanguageExtension::All))))))), + ElementsAre(Eq("ToolChainArgument")))); + + generator.addProjectParts({projectPart1}, {"ToolChainArgument"}); +} + +TEST_F(PchTaskGenerator, RemoveProjectParts) { ON_CALL(mockBuildDependenciesProvider, create(_)).WillByDefault(Return(buildDependency)); - EXPECT_CALL(mockPchTaskMerger, - mergeTasks(ElementsAre( - AllOf(Field(&PchTaskSet::system, - AllOf(Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")), - Field(&PchTask::includes, ElementsAre(4, 5)), - Field(&PchTask::compilerMacros, - ElementsAre(CompilerMacro{"SE", "4", 4}, - CompilerMacro{"WU", "5", 5})), - Field(&PchTask::usedMacros, - ElementsAre(UsedMacro{"SE", 4}, UsedMacro{"WU", 5})))), - AllOf(Field(&PchTaskSet::project, - AllOf(Field(&PchTask::projectPartIds, - ElementsAre("ProjectPart1")), - Field(&PchTask::includes, ElementsAre(1, 3)), - Field(&PchTask::compilerMacros, - ElementsAre(CompilerMacro{"YI", "1", 1}, - CompilerMacro{"SAN", "3", 3})), - Field(&PchTask::usedMacros, - ElementsAre(UsedMacro{"YI", 1}, - UsedMacro{"SAN", 3}))))))))); + EXPECT_CALL( + mockPchTaskMerger, + removePchTasks(ElementsAre("project1", "project2"))); - generator.create({projectPart1}); + generator.removeProjectParts({"project1", "project2"}); } } diff --git a/tests/unit/unittest/pchtaskqueue-test.cpp b/tests/unit/unittest/pchtaskqueue-test.cpp index 2ee1bf3cad..aacd881553 100644 --- a/tests/unit/unittest/pchtaskqueue-test.cpp +++ b/tests/unit/unittest/pchtaskqueue-test.cpp @@ -35,6 +35,9 @@ namespace { +using ClangBackEnd::IncludeSearchPath; +using ClangBackEnd::IncludeSearchPaths; +using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::PchTask; using ClangBackEnd::SlotUsage; @@ -52,42 +55,75 @@ protected: progressCounter, mockPrecompiledHeaderStorage, mockSqliteTransactionBackend}; + IncludeSearchPaths systemIncludeSearchPaths{ + {"/includes", 1, IncludeSearchPathType::BuiltIn}, + {"/other/includes", 2, IncludeSearchPathType::System}}; + IncludeSearchPaths projectIncludeSearchPaths{ + {"/project/includes", 1, IncludeSearchPathType::User}, + {"/other/project/includes", 2, IncludeSearchPathType::User}}; PchTask systemTask1{"ProjectPart1", {1, 2}, {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}}; + {{"LIANG", 0}, {"YI", 1}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; PchTask systemTask2{"ProjectPart2", {1, 2}, {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}}; + {{"LIANG", 0}, {"YI", 1}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; PchTask systemTask2b{"ProjectPart2", {3, 4}, {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}}; + {{"LIANG", 0}, {"YI", 1}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; PchTask systemTask3{"ProjectPart3", {1, 2}, {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}}; + {{"LIANG", 0}, {"YI", 1}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; PchTask projectTask1{"ProjectPart1", {11, 12}, {{"SE", "4", 4}, {"WU", "5", 5}}, - {{"ER", 2}, {"SAN", 3}}}; + {{"ER", 2}, {"SAN", 3}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; PchTask projectTask2{"ProjectPart2", {11, 12}, {{"SE", "4", 4}, {"WU", "5", 5}}, - {{"ER", 2}, {"SAN", 3}}}; + {{"ER", 2}, {"SAN", 3}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; PchTask projectTask2b{"ProjectPart2", {21, 22}, {{"SE", "4", 4}, {"WU", "5", 5}}, - {{"ER", 2}, {"SAN", 3}}}; + {{"ER", 2}, {"SAN", 3}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; PchTask projectTask3{"ProjectPart3", {21, 22}, {{"SE", "4", 4}, {"WU", "5", 5}}, - {{"ER", 2}, {"SAN", 3}}}; + {{"ER", 2}, {"SAN", 3}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; PchTask systemTask4{Utils::SmallStringVector{"ProjectPart1", "ProjectPart3"}, {1, 2}, {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}}; + {{"LIANG", 0}, {"YI", 1}}, + {"--yi"}, + systemIncludeSearchPaths, + projectIncludeSearchPaths}; }; TEST_F(PchTaskQueue, AddProjectPchTask) @@ -111,28 +147,31 @@ TEST_F(PchTaskQueue, AddSystemPchTask) TEST_F(PchTaskQueue, AddProjectPchTasksCallsProcessEntriesForSystemTaskSchedulerIsNotBusy) { InSequence s; + queue.addProjectPchTasks({projectTask1, projectTask2}); EXPECT_CALL(mockSytemPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0})); EXPECT_CALL(mockProjectPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0})); EXPECT_CALL(mockProjectPchTaskScheduler, addTasks(SizeIs(2))); - queue.addProjectPchTasks({projectTask1, projectTask2}); + queue.processEntries(); } TEST_F(PchTaskQueue, AddProjectPchTasksCallsProcessEntriesForSystemTaskSchedulerIsBusy) { InSequence s; + queue.addProjectPchTasks({projectTask1, projectTask2}); EXPECT_CALL(mockSytemPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 1})); EXPECT_CALL(mockProjectPchTaskScheduler, slotUsage()).Times(0); EXPECT_CALL(mockProjectPchTaskScheduler, addTasks(_)).Times(0); - queue.addProjectPchTasks({projectTask1, projectTask2}); + queue.processEntries(); } TEST_F(PchTaskQueue, AddSystemPchTasksCallsProcessEntries) { InSequence s; + queue.addSystemPchTasks({projectTask1, projectTask2}); EXPECT_CALL(mockSytemPchTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0})); EXPECT_CALL(mockSytemPchTaskScheduler, addTasks(SizeIs(2))); @@ -140,7 +179,7 @@ TEST_F(PchTaskQueue, AddSystemPchTasksCallsProcessEntries) EXPECT_CALL(mockProjectPchTaskScheduler, slotUsage()).Times(0); EXPECT_CALL(mockProjectPchTaskScheduler, addTasks(_)).Times(0); - queue.addSystemPchTasks({projectTask1, projectTask2}); + queue.processEntries(); } TEST_F(PchTaskQueue, AddProjectPchTasksCallsProgressCounter) @@ -250,20 +289,13 @@ TEST_F(PchTaskQueue, CreateProjectTaskFromPchTask) auto projectTask = projectTask1; projectTask.systemPchPath = "/path/to/pch"; - EXPECT_CALL(mockSqliteTransactionBackend, lock()); - EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); + EXPECT_CALL(mockPrecompiledHeaderStorage, fetchSystemPrecompiledHeaderPath(Eq("ProjectPart1"))) - .WillOnce(Return(Utils::PathString{"/path/to/pch"})); - EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockSqliteTransactionBackend, unlock()); + .WillOnce(Return(ClangBackEnd::FilePath{"/path/to/pch"})); EXPECT_CALL(mockPchCreator, generatePch(Eq(projectTask))); EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch)); - EXPECT_CALL(mockSqliteTransactionBackend, lock()); - EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockPrecompiledHeaderStorage, insertProjectPrecompiledHeader(Eq("ProjectPart1"), Eq("/path/to/pch"), 99)); - EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockSqliteTransactionBackend, unlock()); tasks.front()(mockPchCreator); } @@ -277,19 +309,11 @@ TEST_F(PchTaskQueue, DeleteProjectPchEntryInDatabaseIfNoPchIsGenerated) auto projectTask = projectTask1; projectTask.systemPchPath = "/path/to/pch"; - EXPECT_CALL(mockSqliteTransactionBackend, lock()); - EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); EXPECT_CALL(mockPrecompiledHeaderStorage, fetchSystemPrecompiledHeaderPath(Eq("ProjectPart1"))) - .WillOnce(Return(Utils::PathString{"/path/to/pch"})); - EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockSqliteTransactionBackend, unlock()); + .WillOnce(Return(ClangBackEnd::FilePath{"/path/to/pch"})); EXPECT_CALL(mockPchCreator, generatePch(Eq(projectTask))); EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch)); - EXPECT_CALL(mockSqliteTransactionBackend, lock()); - EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockPrecompiledHeaderStorage, deleteProjectPrecompiledHeader(Eq("ProjectPart1"))); - EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockSqliteTransactionBackend, unlock()); tasks.front()(mockPchCreator); } @@ -310,14 +334,10 @@ TEST_F(PchTaskQueue, CreateSystemTaskFromPchTask) EXPECT_CALL(mockPchCreator, generatePch(Eq(systemTask4))); EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch)); - EXPECT_CALL(mockSqliteTransactionBackend, lock()); - EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockPrecompiledHeaderStorage, - insertSystemPrecompiledHeader(Eq("ProjectPart1"), Eq("/path/to/pch"), 99)); - EXPECT_CALL(mockPrecompiledHeaderStorage, - insertSystemPrecompiledHeader(Eq("ProjectPart3"), Eq("/path/to/pch"), 99)); - EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockSqliteTransactionBackend, unlock()); + insertSystemPrecompiledHeaders(UnorderedElementsAre("ProjectPart1", "ProjectPart3"), + Eq("/path/to/pch"), + 99)); tasks.front()(mockPchCreator); } @@ -331,12 +351,8 @@ TEST_F(PchTaskQueue, DeleteSystemPchEntryInDatabaseIfNoPchIsGenerated) EXPECT_CALL(mockPchCreator, generatePch(Eq(systemTask4))); EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch)); - EXPECT_CALL(mockSqliteTransactionBackend, lock()); - EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); - EXPECT_CALL(mockPrecompiledHeaderStorage, deleteSystemPrecompiledHeader(Eq("ProjectPart1"))); - EXPECT_CALL(mockPrecompiledHeaderStorage, deleteSystemPrecompiledHeader(Eq("ProjectPart3"))); - EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockSqliteTransactionBackend, unlock()); + EXPECT_CALL(mockPrecompiledHeaderStorage, + deleteSystemPrecompiledHeaders(UnorderedElementsAre("ProjectPart1", "ProjectPart3"))); tasks.front()(mockPchCreator); } diff --git a/tests/unit/unittest/pchtasksmerger-test.cpp b/tests/unit/unittest/pchtasksmerger-test.cpp index 8331e69009..6319389e73 100644 --- a/tests/unit/unittest/pchtasksmerger-test.cpp +++ b/tests/unit/unittest/pchtasksmerger-test.cpp @@ -29,16 +29,21 @@ #include <pchtasksmerger.h> +namespace { + +using ClangBackEnd::IncludeSearchPath; +using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::PchTask; using ClangBackEnd::PchTaskSet; class PchTasksMerger : public testing::Test { protected: - template<class T> - T clone(T entry) + PchTask clone(PchTask entry) const { - return *&entry; + // entry.toolChainArguments = toolChainArguments; + + return entry; } protected: @@ -47,19 +52,44 @@ protected: PchTask systemTask1{"ProjectPart1", {1, 2}, {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}}; + {{"LIANG", 0}, {"YI", 1}}, + {"--yi"}, + {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, + IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, + IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, + {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, + IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; PchTask projectTask1{"ProjectPart1", {11, 12}, {{"SE", "4", 4}, {"WU", "5", 5}}, - {{"ER", 2}, {"SAN", 3}}}; + {{"ER", 2}, {"SAN", 3}}, + {"--yi"}, + {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, + IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, + IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, + {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, + IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; PchTask systemTask2{"ProjectPart2", {1, 2}, {{"YI", "1", 1}, {"SAN", "3", 3}}, - {{"LIANG", 0}, {"YI", 1}}}; + {{"LIANG", 0}, {"YI", 1}}, + {"--yi"}, + {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, + IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, + IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, + {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, + IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; PchTask projectTask2{"ProjectPart2", {11, 12}, {{"SE", "4", 4}, {"WU", "5", 5}}, - {{"ER", 2}, {"SAN", 3}}}; + {{"ER", 2}, {"SAN", 3}}, + {"--yi"}, + {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, + IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, + IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, + {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, + IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}}; + Utils::SmallStringVector toolChainArguments = {"toolChainArguments"}; }; TEST_F(PchTasksMerger, AddProjectTasks) @@ -70,8 +100,8 @@ TEST_F(PchTasksMerger, AddProjectTasks) EXPECT_CALL(mockPchTaskQueue, processEntries()); merger.mergeTasks( - {{clone(systemTask1), clone(projectTask1)}, {clone(systemTask1), clone(projectTask2)}}); - + {{clone(systemTask1), clone(projectTask1)}, {clone(systemTask1), clone(projectTask2)}}, + std::move(toolChainArguments)); } TEST_F(PchTasksMerger, AddSystemTasks) @@ -82,5 +112,14 @@ TEST_F(PchTasksMerger, AddSystemTasks) EXPECT_CALL(mockPchTaskQueue, processEntries()); merger.mergeTasks( - {{clone(systemTask1), clone(projectTask1)}, {clone(systemTask2), clone(projectTask2)}}); + {{clone(systemTask1), clone(projectTask1)}, {clone(systemTask2), clone(projectTask2)}}, + std::move(toolChainArguments)); +} + +TEST_F(PchTasksMerger, RemoveTasks) +{ + EXPECT_CALL(mockPchTaskQueue, removePchTasks(ElementsAre("project1", "project2"))); + + merger.removePchTasks({"project1", "project2"}); +} } diff --git a/tests/unit/unittest/precompiledheaderstorage-test.cpp b/tests/unit/unittest/precompiledheaderstorage-test.cpp index 61fdfb5a88..fb65aa7c80 100644 --- a/tests/unit/unittest/precompiledheaderstorage-test.cpp +++ b/tests/unit/unittest/precompiledheaderstorage-test.cpp @@ -119,7 +119,7 @@ TEST_F(PrecompiledHeaderStorage, DeleteProjectPrecompiledHeaderStatementIsBusy) storage.deleteProjectPrecompiledHeader("project1"); } -TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeader) +TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeaders) { InSequence s; @@ -129,12 +129,17 @@ TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeader) write(TypedEq<Utils::SmallStringView>("project1"), TypedEq<Utils::SmallStringView>("/path/to/pch"), TypedEq<long long>(22))); + EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project2"))); + EXPECT_CALL(insertSystemPrecompiledHeaderStatement, + write(TypedEq<Utils::SmallStringView>("project2"), + TypedEq<Utils::SmallStringView>("/path/to/pch"), + TypedEq<long long>(22))); EXPECT_CALL(database, commit()); - storage.insertSystemPrecompiledHeader("project1", "/path/to/pch", 22); + storage.insertSystemPrecompiledHeaders({"project1", "project2"}, "/path/to/pch", 22); } -TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeaderStatementIsBusy) +TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeadersStatementIsBusy) { InSequence s; @@ -145,32 +150,43 @@ TEST_F(PrecompiledHeaderStorage, InsertSystemPrecompiledHeaderStatementIsBusy) write(TypedEq<Utils::SmallStringView>("project1"), TypedEq<Utils::SmallStringView>("/path/to/pch"), TypedEq<long long>(22))); + EXPECT_CALL(insertProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project2"))); + EXPECT_CALL(insertSystemPrecompiledHeaderStatement, + write(TypedEq<Utils::SmallStringView>("project2"), + TypedEq<Utils::SmallStringView>("/path/to/pch"), + TypedEq<long long>(22))); EXPECT_CALL(database, commit()); - storage.insertSystemPrecompiledHeader("project1", "/path/to/pch", 22); + storage.insertSystemPrecompiledHeaders({"project1", "project2"}, "/path/to/pch", 22); } -TEST_F(PrecompiledHeaderStorage, DeleteSystemPrecompiledHeader) +TEST_F(PrecompiledHeaderStorage, DeleteSystemPrecompiledHeaders) { InSequence s; EXPECT_CALL(database, immediateBegin()); - EXPECT_CALL(deleteSystemPrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1"))); + EXPECT_CALL(deleteSystemPrecompiledHeaderStatement, + write(TypedEq<Utils::SmallStringView>("project1"))); + EXPECT_CALL(deleteSystemPrecompiledHeaderStatement, + write(TypedEq<Utils::SmallStringView>("project2"))); EXPECT_CALL(database, commit()); - storage.deleteSystemPrecompiledHeader("project1"); + storage.deleteSystemPrecompiledHeaders({"project1", "project2"}); } -TEST_F(PrecompiledHeaderStorage, DeleteSystemPrecompiledHeaderStatementIsBusy) +TEST_F(PrecompiledHeaderStorage, DeleteSystemPrecompiledHeadersStatementIsBusy) { InSequence s; EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); EXPECT_CALL(database, immediateBegin()); - EXPECT_CALL(deleteSystemPrecompiledHeaderStatement, write(TypedEq<Utils::SmallStringView>("project1"))); + EXPECT_CALL(deleteSystemPrecompiledHeaderStatement, + write(TypedEq<Utils::SmallStringView>("project1"))); + EXPECT_CALL(deleteSystemPrecompiledHeaderStatement, + write(TypedEq<Utils::SmallStringView>("project2"))); EXPECT_CALL(database, commit()); - storage.deleteSystemPrecompiledHeader("project1"); + storage.deleteSystemPrecompiledHeaders({"project1", "project2"}); } TEST_F(PrecompiledHeaderStorage, CompilePrecompiledHeaderStatements) @@ -187,7 +203,7 @@ TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeaderCalls) EXPECT_CALL(database, deferredBegin()); EXPECT_CALL(fetchSystemPrecompiledHeaderPathStatement, - valueReturnPathString(TypedEq<Utils::SmallStringView>("project1"))); + valueReturnFilePath(TypedEq<Utils::SmallStringView>("project1"))); EXPECT_CALL(database, commit()); storage.fetchSystemPrecompiledHeaderPath("project1"); @@ -196,8 +212,8 @@ TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeaderCalls) TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeader) { EXPECT_CALL(fetchSystemPrecompiledHeaderPathStatement, - valueReturnPathString(TypedEq<Utils::SmallStringView>("project1"))) - .WillOnce(Return(Utils::PathString{"/path/to/pch"})); + valueReturnFilePath(TypedEq<Utils::SmallStringView>("project1"))) + .WillOnce(Return(ClangBackEnd::FilePath{"/path/to/pch"})); auto path = storage.fetchSystemPrecompiledHeaderPath("project1"); @@ -207,8 +223,8 @@ TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeader) TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeaderReturnsEmptyPath) { EXPECT_CALL(fetchSystemPrecompiledHeaderPathStatement, - valueReturnPathString(TypedEq<Utils::SmallStringView>("project1"))) - .WillOnce(Return(Utils::PathString{})); + valueReturnFilePath(TypedEq<Utils::SmallStringView>("project1"))) + .WillOnce(Return(ClangBackEnd::FilePath{})); auto path = storage.fetchSystemPrecompiledHeaderPath("project1"); @@ -218,8 +234,8 @@ TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeaderReturnsEmptyPath) TEST_F(PrecompiledHeaderStorage, FetchSystemPrecompiledHeaderReturnsNullOptional) { EXPECT_CALL(fetchSystemPrecompiledHeaderPathStatement, - valueReturnPathString(TypedEq<Utils::SmallStringView>("project1"))) - .WillOnce(Return(Utils::optional<Utils::PathString>{})); + valueReturnFilePath(TypedEq<Utils::SmallStringView>("project1"))) + .WillOnce(Return(Utils::optional<ClangBackEnd::FilePath>{})); auto path = storage.fetchSystemPrecompiledHeaderPath("project1"); diff --git a/tests/unit/unittest/progresscounter-test.cpp b/tests/unit/unittest/progresscounter-test.cpp index 059bd3bae4..dde6419cc6 100644 --- a/tests/unit/unittest/progresscounter-test.cpp +++ b/tests/unit/unittest/progresscounter-test.cpp @@ -56,6 +56,15 @@ TEST_F(ProgressCounter, AddTotal) counter.addTotal(7); } +TEST_F(ProgressCounter, AddTotalZero) +{ + counter.addTotal(5); + + EXPECT_CALL(mockSetProgressCallback, Call(_, _)).Times(0); + + counter.addTotal(0); +} + TEST_F(ProgressCounter, RemoveTotal) { counter.addTotal(11); @@ -66,6 +75,15 @@ TEST_F(ProgressCounter, RemoveTotal) counter.removeTotal(7); } +TEST_F(ProgressCounter, RemoveTotalZero) +{ + counter.addTotal(11); + + EXPECT_CALL(mockSetProgressCallback, Call(_, _)).Times(0); + + counter.removeTotal(0); +} + TEST_F(ProgressCounter, AddProgress) { counter.addTotal(11); @@ -76,6 +94,16 @@ TEST_F(ProgressCounter, AddProgress) counter.addProgress(4); } +TEST_F(ProgressCounter, AddProgressZero) +{ + counter.addTotal(11); + counter.addProgress(3); + + EXPECT_CALL(mockSetProgressCallback, Call(_, _)).Times(0); + + counter.addProgress(0); +} + TEST_F(ProgressCounter, AddTotalAfterFinishingProgress) { counter.addTotal(11); diff --git a/tests/unit/unittest/projectpartartefact-test.cpp b/tests/unit/unittest/projectpartartefact-test.cpp index f7d3a031a4..b38f15333e 100644 --- a/tests/unit/unittest/projectpartartefact-test.cpp +++ b/tests/unit/unittest/projectpartartefact-test.cpp @@ -30,30 +30,32 @@ namespace { using ClangBackEnd::CompilerMacro; +using ClangBackEnd::IncludeSearchPath; +using ClangBackEnd::IncludeSearchPathType; TEST(ProjectPartArtefact, CompilerArguments) { - ClangBackEnd::ProjectPartArtefact artefact{"[\"-DFoo\",\"-DBar\"]", "", "", 1}; + ClangBackEnd::ProjectPartArtefact artefact{"[\"-DFoo\",\"-DBar\"]", "", "", "", 1}; ASSERT_THAT(artefact.compilerArguments, ElementsAre(Eq("-DFoo"), Eq("-DBar"))); } TEST(ProjectPartArtefact, EmptyCompilerArguments) { - ClangBackEnd::ProjectPartArtefact artefact{"", "", "", 1}; + ClangBackEnd::ProjectPartArtefact artefact{"", "", "", "", 1}; ASSERT_THAT(artefact.compilerArguments, IsEmpty()); } TEST(ProjectPartArtefact, CompilerArgumentsParseError) { - ASSERT_THROW(ClangBackEnd::ProjectPartArtefact("\"-DFoo\",\"-DBar\"]", "", "", 1), + ASSERT_THROW(ClangBackEnd::ProjectPartArtefact("\"-DFoo\",\"-DBar\"]", "", "", "", 1), ClangBackEnd::ProjectPartArtefactParseError); } TEST(ProjectPartArtefact, CompilerMacros) { - ClangBackEnd::ProjectPartArtefact artefact{"", "{\"Foo\":\"1\",\"Bar\":\"42\"}", "", 1}; + ClangBackEnd::ProjectPartArtefact artefact{"", R"([["Foo","1",1], ["Bar","42",2]])", "", "", 1}; ASSERT_THAT(artefact.compilerMacros, UnorderedElementsAre(Eq(CompilerMacro{"Foo", "1", 1}), Eq(CompilerMacro{"Bar", "42", 2}))); @@ -61,35 +63,65 @@ TEST(ProjectPartArtefact, CompilerMacros) TEST(ProjectPartArtefact, EmptyCompilerMacros) { - ClangBackEnd::ProjectPartArtefact artefact{"", "", "", 1}; + ClangBackEnd::ProjectPartArtefact artefact{"", "", "", "", 1}; ASSERT_THAT(artefact.compilerMacros, IsEmpty()); } TEST(ProjectPartArtefact, CompilerMacrosParseError) { - ASSERT_THROW(ClangBackEnd::ProjectPartArtefact("", "\"Foo\":\"1\",\"Bar\":\"42\"}", "", 1), + ASSERT_THROW(ClangBackEnd::ProjectPartArtefact("", R"([["Foo":"1", 1], ["Bar", "42", 2]])", "", "", 1), ClangBackEnd::ProjectPartArtefactParseError); } -TEST(ProjectPartArtefact, IncludeSearchPaths) +TEST(ProjectPartArtefact, SystemIncludeSearchPaths) { - ClangBackEnd::ProjectPartArtefact artefact{"", "", "[\"/includes\",\"/other/includes\"]", 1}; + ClangBackEnd::ProjectPartArtefact artefact{ + "", "", R"([["/includes", 1, 2], ["/other/includes", 2, 3]])", "", 1}; - ASSERT_THAT(artefact.includeSearchPaths, ElementsAre(Eq("/includes"), Eq("/other/includes"))); + ASSERT_THAT( + artefact.systemIncludeSearchPaths, + ElementsAre(Eq(IncludeSearchPath("/includes", 1, IncludeSearchPathType::BuiltIn)), + Eq(IncludeSearchPath("/other/includes", 2, IncludeSearchPathType::System)))); } -TEST(ProjectPartArtefact, EmptyIncludeSearchPaths) +TEST(ProjectPartArtefact, EmptySystemIncludeSearchPaths) { - ClangBackEnd::ProjectPartArtefact artefact{"", "", "", 1}; + ClangBackEnd::ProjectPartArtefact artefact{"", "", "", "", 1}; - ASSERT_THAT(artefact.includeSearchPaths, IsEmpty()); + ASSERT_THAT(artefact.systemIncludeSearchPaths, IsEmpty()); } -TEST(ProjectPartArtefact, IncludeSearchPathsParseError) +TEST(ProjectPartArtefact, ProjectIncludeSearchPaths) { - ASSERT_THROW(ClangBackEnd::ProjectPartArtefact("", "", "\"/includes\",\"/other/includes\"]", 1), - ClangBackEnd::ProjectPartArtefactParseError); + ClangBackEnd::ProjectPartArtefact artefact{ + "", "", R"([["/project/includes", 1, 1], ["/other/project/includes", 2, 1]])", "", 1}; + + ASSERT_THAT( + artefact.systemIncludeSearchPaths, + ElementsAre( + Eq(IncludeSearchPath("/project/includes", 1, IncludeSearchPathType::User)), + Eq(IncludeSearchPath("/other/project/includes", 2, IncludeSearchPathType::User)))); +} + +TEST(ProjectPartArtefact, EmptyProjectIncludeSearchPaths) +{ + ClangBackEnd::ProjectPartArtefact artefact{"", "", "", "", 1}; + + ASSERT_THAT(artefact.projectIncludeSearchPaths, IsEmpty()); } +TEST(ProjectPartArtefact, IncludeSystemSearchPathsParseError) +{ + ASSERT_THROW( + ClangBackEnd::ProjectPartArtefact("", "", R"(["/includes", 1, 3], ["/other/includes", 2, 2]])", "", 1), + ClangBackEnd::ProjectPartArtefactParseError); +} + +TEST(ProjectPartArtefact, IncludeProjectSearchPathsParseError) +{ + ASSERT_THROW( + ClangBackEnd::ProjectPartArtefact("", "", R"(["/project/includes", 1, 1], ["/other/project/includes", 2, 1]])", "", 1), + ClangBackEnd::ProjectPartArtefactParseError); +} } diff --git a/tests/unit/unittest/projectpartqueue-test.cpp b/tests/unit/unittest/projectpartqueue-test.cpp deleted file mode 100644 index 65318a3e91..0000000000 --- a/tests/unit/unittest/projectpartqueue-test.cpp +++ /dev/null @@ -1,183 +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 "mocktaskscheduler.h" -#include "mockpchcreator.h" -#include "mockprecompiledheaderstorage.h" -#include "mocksqlitetransactionbackend.h" - -#include <projectpartqueue.h> -#include <progresscounter.h> - -namespace { - -using ClangBackEnd::SlotUsage; -using ClangBackEnd::V2::ProjectPartContainer; - -class ProjectPartQueue : public testing::Test -{ -protected: - NiceMock<MockTaskScheduler<ClangBackEnd::ProjectPartQueue::Task>> mockTaskScheduler; - MockPrecompiledHeaderStorage mockPrecompiledHeaderStorage; - MockSqliteTransactionBackend mockSqliteTransactionBackend; - NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback; - ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()}; - ClangBackEnd::ProjectPartQueue queue{mockTaskScheduler, mockPrecompiledHeaderStorage, mockSqliteTransactionBackend, progressCounter}; - ClangBackEnd::V2::ProjectPartContainer projectPart1{"ProjectPart1", - {"--yi"}, - {{"YI","1", 1}}, - {"/yi"}, - {1}, - {2}}; - ClangBackEnd::V2::ProjectPartContainer projectPart2{"ProjectPart2", - {"--er"}, - {{"ER","2", 1}}, - {"/bar"}, - {1}, - {2}}; - ClangBackEnd::V2::ProjectPartContainer projectPart2b{"ProjectPart2", - {"--liang"}, - {{"LIANG","3", 1}}, - {"/liang"}, - {3}, - {2, 4}}; - ClangBackEnd::V2::ProjectPartContainer projectPart3{"ProjectPart3", - {"--san"}, - {{"SAN","2", 1}}, - {"/SAN"}, - {1}, - {2}}; -}; - -TEST_F(ProjectPartQueue, AddProjectPart) -{ - queue.addProjectParts({projectPart1}); - - queue.addProjectParts({projectPart2}); - - ASSERT_THAT(queue.projectParts(), ElementsAre(projectPart1, projectPart2)); -} - -TEST_F(ProjectPartQueue, AddProjectPartCallsProcessEntries) -{ - InSequence s; - - EXPECT_CALL(mockTaskScheduler, slotUsage()).WillRepeatedly(Return(SlotUsage{2, 0})); - EXPECT_CALL(mockTaskScheduler, addTasks(SizeIs(2))); - - queue.addProjectParts({projectPart1, projectPart2}); -} - -TEST_F(ProjectPartQueue, AddProjectPartCallsProgressCounter) -{ - queue.addProjectParts({projectPart1, projectPart2}); - - EXPECT_CALL(mockSetProgressCallback, Call(0, 3)); - - queue.addProjectParts({projectPart2b, projectPart3}); -} - -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, RemoveProjectPartCallsProgressCounter) -{ - queue.addProjectParts({projectPart1, projectPart2, projectPart3}); - - EXPECT_CALL(mockSetProgressCallback, Call(0, 2)); - - queue.removeProjectParts({projectPart2.projectPartId}); -} - -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, generatePchDeprecated(Eq(projectPart1))); - EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch)); - EXPECT_CALL(mockSqliteTransactionBackend, lock()); - EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); - EXPECT_CALL(mockPrecompiledHeaderStorage, insertProjectPrecompiledHeader(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, generatePchDeprecated(Eq(projectPart1))); - EXPECT_CALL(mockPchCreator, projectPartPch()).WillOnce(ReturnRef(projectPartPch)); - EXPECT_CALL(mockSqliteTransactionBackend, lock()); - EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); - EXPECT_CALL(mockPrecompiledHeaderStorage, deleteProjectPrecompiledHeader(Eq("project1"))); - EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockSqliteTransactionBackend, unlock()); - - tasks.front()(mockPchCreator); -} - -} diff --git a/tests/unit/unittest/projectparts-test.cpp b/tests/unit/unittest/projectparts-test.cpp index 123a43d28f..87ab509206 100644 --- a/tests/unit/unittest/projectparts-test.cpp +++ b/tests/unit/unittest/projectparts-test.cpp @@ -27,7 +27,7 @@ #include <projectparts.h> -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> namespace { @@ -35,7 +35,7 @@ using testing::ElementsAre; using testing::UnorderedElementsAre; using testing::IsEmpty; -using ClangBackEnd::V2::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainer; using ClangBackEnd::FilePathId; class ProjectParts : public testing::Test @@ -47,24 +47,39 @@ protected: FilePathId firstSource{11}; FilePathId secondSource{12}; FilePathId thirdSource{13}; - ProjectPartContainer projectPartContainer1{"id", - {"-DUNIX", "-O2"}, - {{"DEFINE", "1", 1}}, - {"/includes"}, - {firstHeader, secondHeader}, - {firstSource, secondSource}}; - ProjectPartContainer updatedProjectPartContainer1{"id", - {"-DUNIX", "-O2"}, - {{"DEFINE", "1", 1}}, - {"/includes"}, - {firstHeader, secondHeader}, - {firstSource, secondSource, thirdSource}}; - ProjectPartContainer projectPartContainer2{"id2", - {"-DUNIX", "-O2"}, - {{"DEFINE", "1", 1}}, - {"/includes"}, - {firstHeader, secondHeader}, - {firstSource, secondSource}}; + ProjectPartContainer projectPartContainer1{ + "id", + {"-DUNIX", "-O2"}, + {{"DEFINE", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {firstHeader, secondHeader}, + {firstSource, secondSource}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; + ProjectPartContainer updatedProjectPartContainer1{ + "id", + {"-DUNIX", "-O2"}, + {{"DEFINE", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {firstHeader, secondHeader}, + {firstSource, secondSource, thirdSource}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; + ProjectPartContainer projectPartContainer2{ + "id2", + {"-DUNIX", "-O2"}, + {{"DEFINE", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {firstHeader, secondHeader}, + {firstSource, secondSource}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; }; TEST_F(ProjectParts, GetNoProjectPartsForAddingEmptyProjectParts) diff --git a/tests/unit/unittest/projectupdater-test.cpp b/tests/unit/unittest/projectupdater-test.cpp index 88f438b82c..293a4ef15e 100644 --- a/tests/unit/unittest/projectupdater-test.cpp +++ b/tests/unit/unittest/projectupdater-test.cpp @@ -43,6 +43,7 @@ #include <updategeneratedfilesmessage.h> #include <updateprojectpartsmessage.h> +#include <projectexplorer/projectexplorerconstants.h> #include <cpptools/compileroptionsbuilder.h> #include <cpptools/projectpart.h> @@ -57,8 +58,10 @@ using testing::NiceMock; using testing::AnyNumber; using ClangBackEnd::CompilerMacro; +using ClangBackEnd::IncludeSearchPath; +using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::V2::FileContainer; -using ClangBackEnd::V2::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainer; using CppTools::CompilerOptionsBuilder; using ProjectExplorer::HeaderPath; @@ -96,23 +99,31 @@ protected: projectPartId2 = projectPart2.id(); - Utils::SmallStringVector arguments{ClangPchManager::ProjectUpdater::compilerArguments( + Utils::SmallStringVector arguments{ClangPchManager::ProjectUpdater::toolChainArguments( &projectPart)}; - Utils::SmallStringVector arguments2{ClangPchManager::ProjectUpdater::compilerArguments( + Utils::SmallStringVector arguments2{ClangPchManager::ProjectUpdater::toolChainArguments( &projectPart2)}; expectedContainer = {projectPartId.clone(), arguments.clone(), Utils::clone(compilerMacros), + {{CLANG_RESOURCE_DIR, 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, {}, {filePathId(headerPaths[1])}, - {filePathIds(sourcePaths)}}; + {filePathIds(sourcePaths)}, + Utils::Language::Cxx, + Utils::LanguageVersion::LatestCxx, + Utils::LanguageExtension::None}; expectedContainer2 = {projectPartId2.clone(), arguments2.clone(), Utils::clone(compilerMacros), + {{CLANG_RESOURCE_DIR, 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, {}, {filePathId(headerPaths[1])}, - {filePathIds(sourcePaths)}}; + {filePathIds(sourcePaths)}, + Utils::Language::Cxx, + Utils::LanguageVersion::LatestCxx, + Utils::LanguageExtension::None}; } protected: @@ -145,12 +156,13 @@ protected: TEST_F(ProjectUpdater, CallUpdateProjectParts) { std::vector<CppTools::ProjectPart*> projectParts = {&projectPart2, &projectPart}; - ClangBackEnd::UpdateProjectPartsMessage message{{expectedContainer.clone(), expectedContainer2.clone()}}; + ClangBackEnd::UpdateProjectPartsMessage message{ + {expectedContainer.clone(), expectedContainer2.clone()}, {"toolChainArgument"}}; updater.updateGeneratedFiles({generatedFile}); EXPECT_CALL(mockPchManagerServer, updateProjectParts(message)); - updater.updateProjectParts(projectParts); + updater.updateProjectParts(projectParts, {"toolChainArgument"}); } TEST_F(ProjectUpdater, CallUpdateGeneratedFilesWithSortedEntries) @@ -253,14 +265,109 @@ TEST_F(ProjectUpdater, CreateSortedCompilerMacros) TEST_F(ProjectUpdater, CreateSortedIncludeSearchPaths) { + CppTools::ProjectPart projectPart; ProjectExplorer::HeaderPath includePath{"/to/path1", ProjectExplorer::HeaderPathType::User}; ProjectExplorer::HeaderPath includePath2{"/to/path2", ProjectExplorer::HeaderPathType::User}; ProjectExplorer::HeaderPath invalidPath; - ProjectExplorer::HeaderPath frameworkPath{"/framework/path", ProjectExplorer::HeaderPathType::Framework}; + ProjectExplorer::HeaderPath frameworkPath{"/framework/path", + ProjectExplorer::HeaderPathType::Framework}; + ProjectExplorer::HeaderPath builtInPath{"/builtin/path", ProjectExplorer::HeaderPathType::BuiltIn}; + ProjectExplorer::HeaderPath systemPath{"/system/path", ProjectExplorer::HeaderPathType::System}; + projectPart.headerPaths = { + systemPath, builtInPath, frameworkPath, includePath2, includePath, invalidPath}; + + auto paths = updater.createIncludeSearchPaths(projectPart); + + ASSERT_THAT(paths.system, + ElementsAre(Eq(IncludeSearchPath{systemPath.path, 1, IncludeSearchPathType::System}), + Eq(IncludeSearchPath{builtInPath.path, 4, IncludeSearchPathType::BuiltIn}), + Eq(IncludeSearchPath{frameworkPath.path, 2, IncludeSearchPathType::Framework}), + Eq(IncludeSearchPath{CLANG_RESOURCE_DIR, + 3, + ClangBackEnd::IncludeSearchPathType::BuiltIn}))); + ASSERT_THAT(paths.project, + ElementsAre(Eq(IncludeSearchPath{includePath.path, 2, IncludeSearchPathType::User}), + Eq(IncludeSearchPath{includePath2.path, 1, IncludeSearchPathType::User}))); +} + +TEST_F(ProjectUpdater, ToolChainArguments) +{ + projectPart.toolChainTargetTriple = "target"; + projectPart.extraCodeModelFlags.push_back("extraflags"); + projectPart.compilerFlags.push_back("-fPIC"); + projectPart.projectConfigFile = "config.h"; - auto paths = updater.createIncludeSearchPaths({frameworkPath, includePath2, includePath, invalidPath}); + auto arguments = updater.toolChainArguments(&projectPart); - ASSERT_THAT(paths, ElementsAre(includePath.path, includePath2.path, frameworkPath.path)); + ASSERT_THAT(arguments, + ElementsAre("-m32", "-fPIC", "--target=target", "extraflags", "-include", "config.h")); +} + +TEST_F(ProjectUpdater, ToolChainArgumentsMSVC) +{ + projectPart.toolChainTargetTriple = "target"; + projectPart.extraCodeModelFlags.push_back("extraflags"); + projectPart.toolchainType = ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID; + projectPart.isMsvc2015Toolchain = true; + + auto arguments = updater.toolChainArguments(&projectPart); + + ASSERT_THAT(arguments, + ElementsAre("-m32", + "--target=target", + "extraflags", + "-U__clang__", + "-U__clang_major__", + "-U__clang_minor__", + "-U__clang_patchlevel__", + "-U__clang_version__", + "-U__cpp_aggregate_bases", + "-U__cpp_aggregate_nsdmi", + "-U__cpp_alias_templates", + "-U__cpp_aligned_new", + "-U__cpp_attributes", + "-U__cpp_binary_literals", + "-U__cpp_capture_star_this", + "-U__cpp_constexpr", + "-U__cpp_decltype", + "-U__cpp_decltype_auto", + "-U__cpp_deduction_guides", + "-U__cpp_delegating_constructors", + "-U__cpp_digit_separators", + "-U__cpp_enumerator_attributes", + "-U__cpp_exceptions", + "-U__cpp_fold_expressions", + "-U__cpp_generic_lambdas", + "-U__cpp_guaranteed_copy_elision", + "-U__cpp_hex_float", + "-U__cpp_if_constexpr", + "-U__cpp_inheriting_constructors", + "-U__cpp_init_captures", + "-U__cpp_initializer_lists", + "-U__cpp_inline_variables", + "-U__cpp_lambdas", + "-U__cpp_namespace_attributes", + "-U__cpp_nested_namespace_definitions", + "-U__cpp_noexcept_function_type", + "-U__cpp_nontype_template_args", + "-U__cpp_nontype_template_parameter_auto", + "-U__cpp_nsdmi", + "-U__cpp_range_based_for", + "-U__cpp_raw_strings", + "-U__cpp_ref_qualifiers", + "-U__cpp_return_type_deduction", + "-U__cpp_rtti", + "-U__cpp_rvalue_references", + "-U__cpp_static_assert", + "-U__cpp_structured_bindings", + "-U__cpp_template_auto", + "-U__cpp_threadsafe_static_init", + "-U__cpp_unicode_characters", + "-U__cpp_unicode_literals", + "-U__cpp_user_defined_literals", + "-U__cpp_variable_templates", + "-U__cpp_variadic_templates", + "-U__cpp_variadic_using")); } } diff --git a/tests/unit/unittest/refactoringclientserverinprocess-test.cpp b/tests/unit/unittest/refactoringclientserverinprocess-test.cpp index 55af349bbb..659dcf735f 100644 --- a/tests/unit/unittest/refactoringclientserverinprocess-test.cpp +++ b/tests/unit/unittest/refactoringclientserverinprocess-test.cpp @@ -52,7 +52,7 @@ using ClangBackEnd::RemoveProjectPartsMessage; using ClangBackEnd::UpdateProjectPartsMessage; using ClangBackEnd::UpdateGeneratedFilesMessage; using ClangBackEnd::V2::FileContainer; -using ClangBackEnd::V2::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainer; class RefactoringClientServerInProcess : public ::testing::Test { @@ -192,10 +192,17 @@ TEST_F(RefactoringClientServerInProcess, SendUpdateProjectPartsMessage) ProjectPartContainer projectPart2{"projectPartId", {"-x", "c++-header", "-Wno-pragma-once-outside-header"}, {{"DEFINE", "1", 1}}, - {"/includes"}, + {IncludeSearchPath{"/system/path", 2, IncludeSearchPathType::System}, + IncludeSearchPath{"/builtin/path", 3, IncludeSearchPathType::BuiltIn}, + IncludeSearchPath{"/framework/path", 1, IncludeSearchPathType::System}}, + {IncludeSearchPath{"/to/path1", 1, IncludeSearchPathType::User}, + IncludeSearchPath{"/to/path2", 2, IncludeSearchPathType::User}}, {{1, 1}}, - {{1, 2}}}; - UpdateProjectPartsMessage message{{projectPart2}}; + {{1, 2}}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; + UpdateProjectPartsMessage message{{projectPart2}, {"toolChainArgument"}}; EXPECT_CALL(mockRefactoringServer, updateProjectParts(message)); diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp index 555d742a60..cfae1d80f0 100644 --- a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -88,7 +88,7 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectParts(projectPartId INTEGER PRIMARY KEY, projectPartName TEXT, compilerArguments TEXT, compilerMacros TEXT, includeSearchPaths TEXT)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectParts(projectPartId INTEGER PRIMARY KEY, projectPartName TEXT, compilerArguments TEXT, compilerMacros TEXT, systemIncludeSearchPaths TEXT, projectIncludeSearchPaths TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))); initializer.createProjectPartsTable(); @@ -160,7 +160,7 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor) EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_sources_directoryId_sourceName ON sources(directoryId, sourceName)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS directories(directoryId INTEGER PRIMARY KEY, directoryPath TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_directories_directoryPath ON directories(directoryPath)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectParts(projectPartId INTEGER PRIMARY KEY, projectPartName TEXT, compilerArguments TEXT, compilerMacros TEXT, includeSearchPaths TEXT)"))); + EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectParts(projectPartId INTEGER PRIMARY KEY, projectPartName TEXT, compilerArguments TEXT, compilerMacros TEXT, systemIncludeSearchPaths TEXT, projectIncludeSearchPaths TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, sourceId INTEGER, sourceType INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)"))); diff --git a/tests/unit/unittest/refactoringprojectupdater-test.cpp b/tests/unit/unittest/refactoringprojectupdater-test.cpp index 9c878697a4..ceb6d4b15b 100644 --- a/tests/unit/unittest/refactoringprojectupdater-test.cpp +++ b/tests/unit/unittest/refactoringprojectupdater-test.cpp @@ -52,7 +52,7 @@ MATCHER_P(IsProjectPartContainer, projectPartId, std::string(negation ? "hasn't" : "has") + " name " + std::string(projectPartId)) { - const ClangBackEnd::V2::ProjectPartContainer &container = arg; + const ClangBackEnd::ProjectPartContainer &container = arg; return container.projectPartId == projectPartId; } diff --git a/tests/unit/unittest/refactoringserver-test.cpp b/tests/unit/unittest/refactoringserver-test.cpp index 42fff8dfd5..b8b97437e4 100644 --- a/tests/unit/unittest/refactoringserver-test.cpp +++ b/tests/unit/unittest/refactoringserver-test.cpp @@ -54,18 +54,20 @@ using testing::Property; using testing::_; using ClangBackEnd::FilePath; +using ClangBackEnd::IncludeSearchPaths; +using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::RequestSourceLocationsForRenamingMessage; using ClangBackEnd::RequestSourceRangesAndDiagnosticsForQueryMessage; using ClangBackEnd::RequestSourceRangesForQueryMessage; using ClangBackEnd::SourceLocationsContainer; using ClangBackEnd::SourceLocationsForRenamingMessage; using ClangBackEnd::SourceRangesAndDiagnosticsForQueryMessage; -using ClangBackEnd::SourceRangesForQueryMessage; using ClangBackEnd::SourceRangesContainer; +using ClangBackEnd::SourceRangesForQueryMessage; using ClangBackEnd::V2::FileContainer; using ClangBackEnd::V2::FileContainers; -using ClangBackEnd::V2::ProjectPartContainer; -using ClangBackEnd::V2::ProjectPartContainers; +using ClangBackEnd::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainers; MATCHER_P2(IsSourceLocation, line, column, std::string(negation ? "isn't " : "is ") @@ -325,18 +327,24 @@ TEST_F(RefactoringServer, RemoveGeneratedFilesSetMemberWhichIsUsedForSymbolIndex TEST_F(RefactoringServer, UpdateProjectPartsCallsSymbolIndexingUpdateProjectParts) { - ProjectPartContainers projectParts{{{"projectPartId", - {"-I", TESTDATA_DIR}, - {{"DEFINE", "1", 1}}, - {"/includes"}, - {filePathId("header1.h")}, - {filePathId("main.cpp")}}}}; - + ProjectPartContainers projectParts{ + {{"projectPartId", + {"-I", TESTDATA_DIR}, + {{"DEFINE", "1", 1}}, + IncludeSearchPaths{{"/includes", 1, IncludeSearchPathType::BuiltIn}, + {"/other/includes", 2, IncludeSearchPathType::System}}, + IncludeSearchPaths{{"/project/includes", 1, IncludeSearchPathType::User}, + {"/other/project/includes", 2, IncludeSearchPathType::User}}, + {filePathId("header1.h")}, + {filePathId("main.cpp")}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}}}; EXPECT_CALL(mockSymbolIndexing, updateProjectParts(projectParts)); - refactoringServer.updateProjectParts({Utils::clone(projectParts)}); + refactoringServer.updateProjectParts({Utils::clone(projectParts), {}}); } TEST_F(RefactoringServer, SetProgress) diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index 37dc4071a0..a5ee83b2b8 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -33,7 +33,7 @@ #include <filepathcaching.h> #include <filestatuscache.h> -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> #include <refactoringdatabaseinitializer.h> #include <processormanager.h> #include <symbolindexer.h> @@ -54,8 +54,8 @@ using ClangBackEnd::FileStatuses; using ClangBackEnd::FilePathId; using ClangBackEnd::FilePathIds; using ClangBackEnd::FilePathView; -using ClangBackEnd::V2::ProjectPartContainer; -using ClangBackEnd::V2::ProjectPartContainers; +using ClangBackEnd::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainers; using ClangBackEnd::V2::FileContainers; using ClangBackEnd::SymbolEntries; using ClangBackEnd::SymbolEntry; @@ -164,24 +164,43 @@ protected: ClangBackEnd::FilePathId header1PathId{filePathId(TESTDATA_DIR "/symbolindexer_header2.h")}; PathString generatedFileName = "BuildDependencyCollector_generated_file.h"; ClangBackEnd::FilePathId generatedFilePathId21; + ClangBackEnd::IncludeSearchPaths systemIncludeSearchPaths{ + {"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}, + {TESTDATA_DIR, 2, ClangBackEnd::IncludeSearchPathType::System}, + {"/other/includes", 3, ClangBackEnd::IncludeSearchPathType::System}}; + ClangBackEnd::IncludeSearchPaths projectIncludeSearchPaths{ + {"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}, + {"/other/project/includes", 2, ClangBackEnd::IncludeSearchPathType::User}}; ProjectPartContainer projectPart1{"project1", - {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, + {"-Wno-pragma-once-outside-header"}, {{"BAR", "1", 1}, {"FOO", "1", 2}}, - {"/includes"}, + Utils::clone(systemIncludeSearchPaths), + Utils::clone(projectIncludeSearchPaths), {header1PathId}, - {main1PathId}}; + {main1PathId}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX14, + Utils::LanguageExtension::None}; ProjectPartContainer projectPart2{"project2", - {"-I", TESTDATA_DIR, "-x", "c++-header", "-Wno-pragma-once-outside-header"}, + {"-Wno-pragma-once-outside-header"}, {{"BAR", "1", 1}, {"FOO", "0", 2}}, - {"/includes"}, + Utils::clone(systemIncludeSearchPaths), + Utils::clone(projectIncludeSearchPaths), {header2PathId}, - {main2PathId}}; + {main2PathId}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX14, + Utils::LanguageExtension::None}; ProjectPartContainer projectPart3{"project3", - {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, + {"-Wno-pragma-once-outside-header"}, {{"BAR", "1", 1}, {"FOO", "1", 2}}, - {"/includes", "/other/includes"}, + Utils::clone(systemIncludeSearchPaths), + Utils::clone(projectIncludeSearchPaths), {header1PathId}, - {main1PathId}}; + {main1PathId}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX14, + Utils::LanguageExtension::None}; FileContainers unsaved{{{TESTDATA_DIR, "query_simplefunction.h"}, "void f();", {}}}; @@ -191,8 +210,16 @@ protected: UsedMacros usedMacros{{"Foo", 1}}; FileStatuses fileStatus{{2, 3, 4, false}}; SourceDependencies sourceDependencies{{1, 2}, {1, 3}}; - ClangBackEnd::ProjectPartArtefact artefact{"[\"-DFOO\"]", "{\"FOO\":\"1\",\"BAR\":\"1\"}", "[\"/includes\"]", 74}; - ClangBackEnd::ProjectPartArtefact emptyArtefact{"", "", "", 74}; + Utils::SmallString systemIncludeSearchPathsText{ + R"([["/includes", 1, 2], [")" TESTDATA_DIR R"(" ,2 , 3], ["/other/includes", 3, 3]])"}; + Utils::SmallString projectIncludeSearchPathsText{ + R"([["/project/includes", 1, 1], ["/other/project/includes", 2, 1]])"}; + ClangBackEnd::ProjectPartArtefact artefact{R"(["-DFOO"])", + R"([["FOO","1", 2],["BAR","1", 1]])", + systemIncludeSearchPathsText, + projectIncludeSearchPathsText, + 74}; + ClangBackEnd::ProjectPartArtefact emptyArtefact{"", "", "", "", 74}; Utils::optional<ClangBackEnd::ProjectPartArtefact > nullArtefact; ClangBackEnd::ProjectPartPch projectPartPch{"/path/to/pch", 4}; NiceMock<MockSqliteTransactionBackend> mockSqliteTransactionBackend; @@ -204,7 +231,11 @@ protected: Manager collectorManger{generatedFiles}; NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback; ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()}; - Scheduler indexerScheduler{collectorManger, indexerQueue, progressCounter, 1}; + Scheduler indexerScheduler{collectorManger, + indexerQueue, + progressCounter, + 1, + ClangBackEnd::CallDoInMainThreadAfterFinished::Yes}; SymbolIndexerTaskQueue indexerQueue{indexerScheduler, progressCounter}; ClangBackEnd::SymbolIndexer indexer{indexerQueue, mockSymbolStorage, @@ -220,7 +251,25 @@ std::unique_ptr<Data> SymbolIndexer::data; TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector) { - EXPECT_CALL(mockCollector, setFile(main1PathId, projectPart1.arguments)); + EXPECT_CALL(mockCollector, + setFile(main1PathId, + ElementsAre("clang++", + "-Wno-pragma-once-outside-header", + "-x", + "c++-header", + "-std=c++14", + "-nostdinc", + "-nostdlibinc", + "-I", + "/project/includes", + "-I", + "/other/project/includes", + "-isystem", + TESTDATA_DIR, + "-isystem", + "/other/includes", + "-isystem", + "/includes"))); indexer.updateProjectParts({projectPart1}); } @@ -230,14 +279,29 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithPrecompiledHeaderInColl ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>(projectPart1.projectPartId))).WillByDefault(Return(emptyArtefact)); ON_CALL(mockSymbolStorage, fetchPrecompiledHeader(Eq(artefact.projectPartId))).WillByDefault(Return(projectPartPch)); - EXPECT_CALL(mockCollector, setFile(main1PathId, - ElementsAre(Eq("-I"), - Eq(TESTDATA_DIR), - Eq("-Wno-pragma-once-outside-header"), - Eq("-Xclang"), - Eq("-include-pch"), - Eq("-Xclang"), - Eq("/path/to/pch")))); + EXPECT_CALL(mockCollector, + setFile(main1PathId, + ElementsAre("clang++", + "-Wno-pragma-once-outside-header", + "-x", + "c++-header", + "-std=c++14", + "-nostdinc", + "-nostdlibinc", + "-I", + "/project/includes", + "-I", + "/other/project/includes", + "-isystem", + TESTDATA_DIR, + "-isystem", + "/other/includes", + "-isystem", + "/includes", + "-Xclang", + "-include-pch", + "-Xclang", + "/path/to/pch"))); indexer.updateProjectParts({projectPart1}); } @@ -246,10 +310,25 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithoutPrecompiledHeaderInC { ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>(projectPart1.projectPartId))).WillByDefault(Return(emptyArtefact)); - EXPECT_CALL(mockCollector, setFile(main1PathId, - ElementsAre(Eq("-I"), - Eq(TESTDATA_DIR), - Eq("-Wno-pragma-once-outside-header")))); + EXPECT_CALL(mockCollector, + setFile(main1PathId, + ElementsAre("clang++", + "-Wno-pragma-once-outside-header", + "-x", + "c++-header", + "-std=c++14", + "-nostdinc", + "-nostdlibinc", + "-I", + "/project/includes", + "-I", + "/other/project/includes", + "-isystem", + TESTDATA_DIR, + "-isystem", + "/other/includes", + "-isystem", + "/includes"))); indexer.updateProjectParts({projectPart1}); } @@ -313,14 +392,21 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddSymbolsAndSourceLocationsInStora TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartsInStorage) { - EXPECT_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project1"), - ElementsAre("-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"), - ElementsAre(CompilerMacro{"BAR", "1", 1}, CompilerMacro{"FOO", "1", 2}), - ElementsAre("/includes"))); - EXPECT_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project2"), - ElementsAre("-I", TESTDATA_DIR, "-x", "c++-header", "-Wno-pragma-once-outside-header"), - ElementsAre(CompilerMacro{"BAR", "1", 1}, CompilerMacro{"FOO", "0", 2}), - ElementsAre("/includes"))); + EXPECT_CALL(mockSymbolStorage, + insertOrUpdateProjectPart( + Eq("project1"), + ElementsAre("-Wno-pragma-once-outside-header"), + ElementsAre(CompilerMacro{"BAR", "1", 1}, CompilerMacro{"FOO", "1", 2}), + Eq(systemIncludeSearchPaths), + Eq(projectIncludeSearchPaths))); + EXPECT_CALL( + mockSymbolStorage, + insertOrUpdateProjectPart( + Eq("project2"), + ElementsAre("-Wno-pragma-once-outside-header"), + ElementsAre(CompilerMacro{"BAR", "1", 1}, CompilerMacro{"FOO", "0", 2}), + Eq(systemIncludeSearchPaths), + Eq(projectIncludeSearchPaths))); indexer.updateProjectParts({projectPart1, projectPart2}); } @@ -328,7 +414,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartsInStorage) TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartSourcesWithArtifact) { ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>("project1"))).WillByDefault(Return(artefact)); - ON_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project1"), _, _, _)).WillByDefault(Return(-1)); + ON_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project1"), _, _, _, _)).WillByDefault(Return(-1)); EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(_, _)); @@ -338,7 +424,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartSourcesWithArtifac TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartSourcesWithoutArtifact) { ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>("project2"))).WillByDefault(Return(nullArtefact)); - ON_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project2"), _, _, _)).WillByDefault(Return(3)); + ON_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project2"), _, _, _, _)).WillByDefault(Return(3)); EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(3, ElementsAre(IsFileId(1), IsFileId(23)))); @@ -383,11 +469,35 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact) EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>(projectPart1.projectPartId))).WillOnce(Return(nullArtefact)); - EXPECT_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), Eq(projectPart1.arguments), Eq(projectPart1.compilerMacros), Eq(projectPart1.includeSearchPaths))).WillOnce(Return(12)); + EXPECT_CALL(mockSymbolStorage, + insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), + Eq(projectPart1.toolChainArguments), + Eq(projectPart1.compilerMacros), + Eq(projectPart1.systemIncludeSearchPaths), + Eq(projectPart1.projectIncludeSearchPaths))) + .WillOnce(Return(12)); EXPECT_CALL(mockSymbolStorage, fetchPrecompiledHeader(Eq(12))); EXPECT_CALL(mockBuildDependenciesStorage, fetchLowestLastModifiedTime(Eq(main1PathId))).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockCollector, setFile(main1PathId, projectPart1.arguments)); + EXPECT_CALL(mockCollector, + setFile(main1PathId, + ElementsAre("clang++", + "-Wno-pragma-once-outside-header", + "-x", + "c++-header", + "-std=c++14", + "-nostdinc", + "-nostdlibinc", + "-I", + "/project/includes", + "-I", + "/other/project/includes", + "-isystem", + TESTDATA_DIR, + "-isystem", + "/other/includes", + "-isystem", + "/includes"))); EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); @@ -406,11 +516,35 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact) EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>(projectPart1.projectPartId))).WillRepeatedly(Return(artefact)); - EXPECT_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), Eq(projectPart1.arguments), Eq(projectPart1.compilerMacros), Eq(projectPart1.includeSearchPaths))).WillOnce(Return(-1)); + EXPECT_CALL(mockSymbolStorage, + insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), + Eq(projectPart1.toolChainArguments), + Eq(projectPart1.compilerMacros), + Eq(projectPart1.systemIncludeSearchPaths), + Eq(projectPart1.projectIncludeSearchPaths))) + .WillOnce(Return(-1)); EXPECT_CALL(mockSymbolStorage, fetchPrecompiledHeader(Eq(artefact.projectPartId))); EXPECT_CALL(mockBuildDependenciesStorage, fetchLowestLastModifiedTime(Eq(main1PathId))).WillOnce(Return(-1)); EXPECT_CALL(mockSqliteTransactionBackend, commit()); - EXPECT_CALL(mockCollector, setFile(Eq(main1PathId), Eq(projectPart1.arguments))); + EXPECT_CALL(mockCollector, + setFile(Eq(main1PathId), + ElementsAre("clang++", + "-Wno-pragma-once-outside-header", + "-x", + "c++-header", + "-std=c++14", + "-nostdinc", + "-nostdlibinc", + "-I", + "/project/includes", + "-I", + "/other/project/includes", + "-isystem", + TESTDATA_DIR, + "-isystem", + "/other/includes", + "-isystem", + "/includes"))); EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); @@ -531,22 +665,57 @@ TEST_F(SymbolIndexer, CompilerMacrosAreDifferent) ASSERT_TRUE(areDifferent); } -TEST_F(SymbolIndexer, IncludeSearchPathsAreDifferent) +TEST_F(SymbolIndexer, SystemIncludeSearchPathsAreDifferent) +{ + ClangBackEnd::IncludeSearchPaths newSystemIncludeSearchPaths{ + {"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}, + {"/other/includes2", 2, ClangBackEnd::IncludeSearchPathType::System}}; + ClangBackEnd::IncludeSearchPaths newProjectIncludeSearchPaths{ + {"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}, + {"/other/project/includes2", 2, ClangBackEnd::IncludeSearchPathType::User}}; + ProjectPartContainer projectPart3{ + "project3", + {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, + {{"BAR", "1", 1}, {"FOO", "1", 2}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}, + {"/other/includes2", 2, ClangBackEnd::IncludeSearchPathType::System}}, + Utils::clone(projectIncludeSearchPaths), + {header1PathId}, + {main1PathId}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; + ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(An<Utils::SmallStringView>())) + .WillByDefault(Return(artefact)); + + auto areDifferent = indexer.compilerMacrosOrIncludeSearchPathsAreDifferent( + projectPart3, artefact); + + ASSERT_TRUE(areDifferent); +} + +TEST_F(SymbolIndexer, ProjectIncludeSearchPathsAreDifferent) { - ProjectPartContainer projectPart3{"project3", - {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, - {{"BAR", "1", 1}, {"FOO", "1", 2}}, - {"/includes", "/other/includes"}, - {header1PathId}, - {main1PathId}}; - ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(An<Utils::SmallStringView>())).WillByDefault(Return(artefact)); + ProjectPartContainer projectPart3{ + "project3", + {"-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header"}, + {{"BAR", "1", 1}, {"FOO", "1", 2}}, + Utils::clone(systemIncludeSearchPaths), + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}, + {"/other/project/includes2", 2, ClangBackEnd::IncludeSearchPathType::User}}, + {header1PathId}, + {main1PathId}, + Utils::Language::C, + Utils::LanguageVersion::C11, + Utils::LanguageExtension::All}; + ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(An<Utils::SmallStringView>())) + .WillByDefault(Return(artefact)); - auto areDifferent = indexer.compilerMacrosOrIncludeSearchPathsAreDifferent(projectPart3, - artefact); + auto areDifferent = indexer.compilerMacrosOrIncludeSearchPathsAreDifferent( + projectPart3, artefact); ASSERT_TRUE(areDifferent); } - TEST_F(SymbolIndexer, DontReparseInUpdateProjectPartsIfDefinesAreTheSame) { InSequence s; @@ -554,7 +723,12 @@ TEST_F(SymbolIndexer, DontReparseInUpdateProjectPartsIfDefinesAreTheSame) EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq<Utils::SmallStringView>(projectPart1.projectPartId))).WillRepeatedly(Return(artefact)); - EXPECT_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), Eq(projectPart1.arguments), Eq(projectPart1.compilerMacros), Eq(projectPart1.includeSearchPaths))); + EXPECT_CALL(mockSymbolStorage, + insertOrUpdateProjectPart(Eq(projectPart1.projectPartId), + Eq(projectPart1.toolChainArguments), + Eq(projectPart1.compilerMacros), + Eq(projectPart1.systemIncludeSearchPaths), + Eq(projectPart1.projectIncludeSearchPaths))); EXPECT_CALL(mockBuildDependenciesStorage, fetchLowestLastModifiedTime(A<FilePathId>())).WillRepeatedly(Return(QDateTime::currentSecsSinceEpoch())); EXPECT_CALL(mockSqliteTransactionBackend, commit()); EXPECT_CALL(mockCollector, setFile(_, _)).Times(0); @@ -649,6 +823,7 @@ TEST_F(SymbolIndexer, OutdatedFilesAreParsedInUpdateProjectParts) TEST_F(SymbolIndexer, UpToDateFilesAreNotParsedInUpdateProjectParts) { indexer.pathsChanged({main1PathId}); + indexerScheduler.syncTasks(); ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(An<Utils::SmallStringView>())).WillByDefault(Return(artefact)); ON_CALL(mockBuildDependenciesStorage, fetchLowestLastModifiedTime(A<FilePathId>())) diff --git a/tests/unit/unittest/symbolindexing-test.cpp b/tests/unit/unittest/symbolindexing-test.cpp index 68a2cb8c65..41bf3a5c3b 100644 --- a/tests/unit/unittest/symbolindexing-test.cpp +++ b/tests/unit/unittest/symbolindexing-test.cpp @@ -30,7 +30,7 @@ #include <querysqlitestatementfactory.h> #include <filepathcaching.h> -#include <projectpartcontainerv2.h> +#include <projectpartcontainer.h> #include <refactoringdatabaseinitializer.h> #include <QDir> @@ -45,8 +45,8 @@ using ClangBackEnd::SymbolStorage; using ClangBackEnd::FilePathCaching; using ClangBackEnd::FilePathId; using ClangBackEnd::RefactoringDatabaseInitializer; -using ClangBackEnd::V2::ProjectPartContainer; -using ClangBackEnd::V2::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainer; +using ClangBackEnd::ProjectPartContainer; using ClangRefactoring::SymbolQuery; using ClangRefactoring::QuerySqliteStatementFactory; using Utils::PathString; @@ -88,11 +88,15 @@ protected: Query query{queryFactory}; PathString main1Path = TESTDATA_DIR "/symbolindexing_main1.cpp"; ProjectPartContainer projectPart1{"project1", - {"cc", "-I", TESTDATA_DIR, "-std=c++1z"}, + {}, {{"DEFINE", "1", 1}}, - {"/includes"}, + {{TESTDATA_DIR, 1, ClangBackEnd::IncludeSearchPathType::System}}, + {}, {}, - {filePathId(main1Path)}}; + {filePathId(main1Path)}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX14, + Utils::LanguageExtension::None}; }; TEST_F(SymbolIndexing, Locations) diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index 266540c62b..4a3958212b 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -35,18 +35,21 @@ namespace { -using Utils::PathString; -using ClangBackEnd::FilePathId; using ClangBackEnd::FilePathCachingInterface; -using ClangBackEnd::SymbolEntries; -using ClangBackEnd::SymbolEntry; +using ClangBackEnd::FilePathId; +using ClangBackEnd::IncludeSearchPath; +using ClangBackEnd::IncludeSearchPaths; +using ClangBackEnd::IncludeSearchPathType; using ClangBackEnd::SourceLocationEntries; using ClangBackEnd::SourceLocationEntry; -using ClangBackEnd::SymbolIndex; using ClangBackEnd::SourceLocationKind; +using ClangBackEnd::SymbolEntries; +using ClangBackEnd::SymbolEntry; +using ClangBackEnd::SymbolIndex; using ClangBackEnd::SymbolKind; using Sqlite::Database; using Sqlite::Table; +using Utils::PathString; using Storage = ClangBackEnd::SymbolStorage<MockSqliteDatabase>; @@ -65,8 +68,7 @@ protected: MockSqliteWriteStatement &insertNewLocationsInLocationsStatement = storage.m_insertNewLocationsInLocationsStatement; MockSqliteWriteStatement &deleteNewSymbolsTableStatement = storage.m_deleteNewSymbolsTableStatement; MockSqliteWriteStatement &deleteNewLocationsTableStatement = storage.m_deleteNewLocationsTableStatement; - MockSqliteWriteStatement &insertProjectPartStatement = storage.m_insertProjectPartStatement; - MockSqliteWriteStatement &updateProjectPartStatement = storage.m_updateProjectPartStatement; + MockSqliteWriteStatement &insertOrUpdateProjectPartStatement = storage.m_insertOrUpdateProjectPartStatement; MockSqliteReadStatement &getProjectPartIdStatement = storage.m_getProjectPartIdStatement; MockSqliteWriteStatement &deleteAllProjectPartsSourcesWithProjectPartIdStatement = storage.m_deleteAllProjectPartsSourcesWithProjectPartIdStatement; MockSqliteWriteStatement &insertProjectPartSourcesStatement = storage.m_insertProjectPartSourcesStatement; @@ -78,7 +80,21 @@ protected: {2, {"function2USR", "function2", SymbolKind::Function}}}; SourceLocationEntries sourceLocations{{1, 3, {42, 23}, SourceLocationKind::Declaration}, {2, 4, {7, 11}, SourceLocationKind::Definition}}; - ClangBackEnd::ProjectPartArtefact artefact{"[\"-DFOO\"]", "{\"FOO\":\"1\"}", "[\"/includes\"]", 74}; + IncludeSearchPaths systemIncludeSearchPaths{ + {"/includes", 1, IncludeSearchPathType::BuiltIn}, + {"/other/includes", 2, IncludeSearchPathType::System}}; + IncludeSearchPaths projectIncludeSearchPaths{ + {"/project/includes", 1, IncludeSearchPathType::User}, + {"/other/project/includes", 2, IncludeSearchPathType::User}}; + Utils::SmallString systemIncludeSearchPathsText{ + R"([["/includes",1,2],["/other/includes",2,3]])"}; + Utils::SmallString projectIncludeSearchPathsText{ + R"([["/project/includes",1,1],["/other/project/includes",2,1]])"}; + ClangBackEnd::ProjectPartArtefact artefact{R"(["-DFOO"])", + R"([["FOO","1",1]])", + systemIncludeSearchPathsText, + projectIncludeSearchPathsText, + 74}; }; TEST_F(SymbolStorage, CreateAndFillTemporaryLocationsTable) @@ -167,43 +183,24 @@ TEST_F(SymbolStorage, ConvertStringsToJson) ASSERT_THAT(jsonText, Eq("[\"foo\",\"bar\",\"foo\"]")); } -TEST_F(SymbolStorage, InsertProjectPart) +TEST_F(SymbolStorage, InsertOrUpdateProjectPart) { InSequence sequence; - ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(1)); - EXPECT_CALL(mockDatabase, setLastInsertedRowId(-1)); - EXPECT_CALL(insertProjectPartStatement, + EXPECT_CALL(insertOrUpdateProjectPartStatement, write(TypedEq<Utils::SmallStringView>("project"), - TypedEq<Utils::SmallStringView>("[\"foo\"]"), - TypedEq<Utils::SmallStringView>("{\"FOO\":\"1\"}"), - TypedEq<Utils::SmallStringView>("[\"/includes\"]"))); - EXPECT_CALL(mockDatabase, lastInsertedRowId()).Times(2); - - storage.insertOrUpdateProjectPart("project", {"foo"}, {{"FOO", "1", 1}}, {"/includes"}); + TypedEq<Utils::SmallStringView>(R"(["foo"])"), + TypedEq<Utils::SmallStringView>(R"([["FOO","1",1]])"), + TypedEq<Utils::SmallStringView>(systemIncludeSearchPathsText), + TypedEq<Utils::SmallStringView>(projectIncludeSearchPathsText))); + EXPECT_CALL( + getProjectPartIdStatement, valueReturnInt32(TypedEq<Utils::SmallStringView>("project"))) + .WillOnce(Return(74)); + + storage.insertOrUpdateProjectPart( + "project", {"foo"}, {{"FOO", "1", 1}}, systemIncludeSearchPaths, projectIncludeSearchPaths); } -TEST_F(SymbolStorage, UpdateProjectPart) -{ - InSequence sequence; - ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(-1)); - - EXPECT_CALL(mockDatabase, setLastInsertedRowId(-1)); - EXPECT_CALL(insertProjectPartStatement, - write(TypedEq<Utils::SmallStringView>("project"), - TypedEq<Utils::SmallStringView>("[\"foo\"]"), - TypedEq<Utils::SmallStringView>("{\"FOO\":\"1\"}"), - TypedEq<Utils::SmallStringView>("[\"/includes\"]"))); - EXPECT_CALL(mockDatabase, lastInsertedRowId()); - EXPECT_CALL(updateProjectPartStatement, - write(TypedEq<Utils::SmallStringView>("[\"foo\"]"), - TypedEq<Utils::SmallStringView>("{\"FOO\":\"1\"}"), - TypedEq<Utils::SmallStringView>("[\"/includes\"]"), - TypedEq<Utils::SmallStringView>("project"))); - EXPECT_CALL(mockDatabase, lastInsertedRowId()); - - storage.insertOrUpdateProjectPart("project", {"foo"}, {{"FOO", "1", 1}}, {"/includes"}); -} TEST_F(SymbolStorage, UpdateProjectPartSources) { diff --git a/tests/unit/unittest/taskscheduler-test.cpp b/tests/unit/unittest/taskscheduler-test.cpp index 9afc52a724..7b6d0bbcbf 100644 --- a/tests/unit/unittest/taskscheduler-test.cpp +++ b/tests/unit/unittest/taskscheduler-test.cpp @@ -68,14 +68,16 @@ protected: NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback; ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()}; Scheduler scheduler{mockProcessorManager, - mockSymbolIndexerTaskQueue, - progressCounter, - 4}; + mockSymbolIndexerTaskQueue, + progressCounter, + 4, + ClangBackEnd::CallDoInMainThreadAfterFinished::Yes}; Scheduler deferredScheduler{mockProcessorManager, - mockSymbolIndexerTaskQueue, - progressCounter, - 4, - std::launch::deferred}; + mockSymbolIndexerTaskQueue, + progressCounter, + 4, + ClangBackEnd::CallDoInMainThreadAfterFinished::Yes, + std::launch::deferred}; }; TEST_F(TaskScheduler, AddTasks) @@ -146,6 +148,24 @@ TEST_F(TaskScheduler, FreeSlotsCallsCleanupMethodsAfterTheWorkIsDone) scheduler.slotUsage(); } +TEST_F(TaskScheduler, FreeSlotsDoNotCallsDoInMainThreadAfterFinishedAfterTheWorkIsDoneIfForbidden) +{ + Scheduler scheduler{mockProcessorManager, + mockSymbolIndexerTaskQueue, + progressCounter, + 4, + ClangBackEnd::CallDoInMainThreadAfterFinished::No}; + scheduler.addTasks({nocall, nocall}); + scheduler.syncTasks(); + InSequence s; + + EXPECT_CALL(mockSymbolsCollector, doInMainThreadAfterFinished()).Times(0); + + scheduler.slotUsage(); + scheduler.syncTasks(); + QCoreApplication::processEvents(); +} + TEST_F(TaskScheduler, FreeSlotsCallsProgressMethodsAfterTheWorkIsDone) { scheduler.addTasks({nocall, nocall}); diff --git a/tests/unit/unittest/testenvironment.h b/tests/unit/unittest/testenvironment.h index 8b6ef89710..a9529c58d5 100644 --- a/tests/unit/unittest/testenvironment.h +++ b/tests/unit/unittest/testenvironment.h @@ -44,11 +44,6 @@ public: return temporaryDirectory.path(); } - QString clangCompilerPath() const override - { - return QString::fromUtf8(CLANG_COMPILER_PATH); - } - uint hardwareConcurrency() const { return 2; diff --git a/tests/unit/unittest/toolchainargumentscache-test.cpp b/tests/unit/unittest/toolchainargumentscache-test.cpp new file mode 100644 index 0000000000..8f032fa43d --- /dev/null +++ b/tests/unit/unittest/toolchainargumentscache-test.cpp @@ -0,0 +1,199 @@ +/**************************************************************************** +** +** 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 <toolchainargumentscache.h> + +namespace { + +using ClangBackEnd::ProjectPartContainer; + +MATCHER_P2(IsEntry, + projectPartIds, + arguments, + std::string(negation ? "isn't " : "is ") + + PrintToString(ClangBackEnd::ArgumentsEntry(projectPartIds.clone(), arguments))) +{ + const ClangBackEnd::ArgumentsEntry &entry= arg; + + return entry.ids == projectPartIds && entry.arguments == arguments; +} + +class ToolChainArgumentsCache : public testing::Test +{ +public: + ClangBackEnd::ToolChainsArgumentsCache cache; + ProjectPartContainer projectPart1{"project1", {}, {}, {}, {}, {}, {}, {}, {}, {}}; + ProjectPartContainer projectPart2{"project2", {}, {}, {}, {}, {}, {}, {}, {}, {}}; + ProjectPartContainer projectPart3{"project3", {}, {}, {}, {}, {}, {}, {}, {}, {}}; + ProjectPartContainer projectPart4{"project4", {}, {}, {}, {}, {}, {}, {}, {}, {}}; + Utils::SmallStringVector arguments1{"yi", "er"}; + Utils::SmallStringVector arguments2{"san", "se"}; +}; + +TEST_F(ToolChainArgumentsCache, ArgumentsDoesNotExistForProjectPartId) +{ + cache.update({projectPart2, projectPart4}, arguments2); + + ASSERT_THAT(cache.arguments({projectPart1.projectPartId}), IsEmpty()); +} + +TEST_F(ToolChainArgumentsCache, AddNewArguments) +{ + cache.update({projectPart2, projectPart4}, arguments2); + + cache.update({projectPart1, projectPart3}, arguments1); + + ASSERT_THAT( + cache.arguments({projectPart1.projectPartId}), + ElementsAre(IsEntry(Utils::SmallStringVector{projectPart1.projectPartId}, arguments1))); +} + +TEST_F(ToolChainArgumentsCache, AddDifferentProjectParts) +{ + cache.update({projectPart1, projectPart3}, arguments1); + + cache.update({projectPart2, projectPart4}, arguments1); + + ASSERT_THAT( + cache.arguments(Utils::SmallStringVector{projectPart2.projectPartId}), + ElementsAre(IsEntry(Utils::SmallStringVector{projectPart2.projectPartId}, arguments1))); +} + +TEST_F(ToolChainArgumentsCache, AddDifferentProjectPartsReverseOrder) +{ + cache.update({projectPart2, projectPart3}, arguments1); + + cache.update({projectPart1, projectPart4}, arguments1); + + ASSERT_THAT( + cache.arguments(Utils::SmallStringVector{projectPart2.projectPartId}), + ElementsAre(IsEntry(Utils::SmallStringVector{projectPart2.projectPartId}, arguments1))); +} + +TEST_F(ToolChainArgumentsCache, AddDifferentProjectPartsDoesNotRemoveOldEntry) +{ + cache.update({projectPart1, projectPart3}, arguments1); + + cache.update({projectPart2, projectPart4}, arguments1); + + ASSERT_THAT( + cache.arguments(Utils::SmallStringVector{projectPart1.projectPartId}), + ElementsAre(IsEntry(Utils::SmallStringVector{projectPart1.projectPartId}, arguments1))); +} + +TEST_F(ToolChainArgumentsCache, AddSameArgumentsDoesNotIncreseEntryCount) +{ + cache.update({projectPart1, projectPart3}, arguments1); + + cache.update({projectPart2, projectPart4}, arguments1); + + ASSERT_THAT(cache.size(), 1); +} + +TEST_F(ToolChainArgumentsCache, AddDifferentArgumentsDoesIncreseEntryCount) +{ + cache.update({projectPart1, projectPart3}, arguments1); + + cache.update({projectPart2, projectPart4}, arguments2); + + ASSERT_THAT(cache.size(), 2); +} + +TEST_F(ToolChainArgumentsCache, RemoveIdsFromOtherEntries) +{ + cache.update({projectPart2, projectPart4}, arguments1); + cache.update({projectPart1, projectPart3}, arguments1); + + cache.update({projectPart2, projectPart4}, arguments2); + + ASSERT_THAT( + cache.arguments(Utils::SmallStringVector{projectPart2.projectPartId}), + ElementsAre(IsEntry(Utils::SmallStringVector{projectPart2.projectPartId}, arguments2))); +} + +TEST_F(ToolChainArgumentsCache, RemoveIdsFromOtherEntriesWithArgumentsAlreadyExists) +{ + cache.update({projectPart2, projectPart4}, arguments1); + cache.update({projectPart1, projectPart3}, arguments2); + + cache.update({projectPart2, projectPart4}, arguments2); + + ASSERT_THAT( + cache.arguments({projectPart2.projectPartId}), + ElementsAre(IsEntry(Utils::SmallStringVector{projectPart2.projectPartId}, arguments2))); +} + +TEST_F(ToolChainArgumentsCache, RemoveEntryIfEmpty) +{ + cache.update({projectPart2, projectPart4}, arguments2); + cache.update({projectPart1, projectPart3}, arguments1); + + cache.update({projectPart2, projectPart4}, arguments1); + + ASSERT_THAT(cache.size(), 1); +} + +TEST_F(ToolChainArgumentsCache, GetMutipleEntries) +{ + cache.update({projectPart2, projectPart4}, arguments1); + cache.update({projectPart1, projectPart3}, arguments2); + + auto arguments = cache.arguments( + {projectPart1.projectPartId, projectPart2.projectPartId, projectPart3.projectPartId}); + + ASSERT_THAT( + arguments, + ElementsAre(IsEntry(Utils::SmallStringVector{projectPart2.projectPartId}, arguments1), + IsEntry(Utils::SmallStringVector{projectPart1.projectPartId, + projectPart3.projectPartId}, + arguments2))); +} + +TEST_F(ToolChainArgumentsCache, RemoveMutipleIds) +{ + cache.update({projectPart2, projectPart4}, arguments1); + cache.update({projectPart1, projectPart3}, arguments2); + + cache.remove({projectPart1.projectPartId, projectPart2.projectPartId}); + + ASSERT_THAT( + cache.arguments( + {projectPart1.projectPartId, projectPart2.projectPartId, projectPart3.projectPartId}), + ElementsAre(IsEntry(Utils::SmallStringVector{projectPart3.projectPartId}, arguments2))); +} + +TEST_F(ToolChainArgumentsCache, RemoveEntriesIfEntryIsEmptyAfterRemovingIds) +{ + cache.update({projectPart2, projectPart4}, arguments1); + cache.update({projectPart1, projectPart3}, arguments2); + + cache.remove({projectPart1.projectPartId, projectPart3.projectPartId}); + + ASSERT_THAT(cache.size(), 1); +} + +} // namespace diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index f6eded4a58..431207371d 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -99,7 +99,6 @@ SOURCES += \ sourcesmanager-test.cpp \ symbolindexertaskqueue-test.cpp \ refactoringprojectupdater-test.cpp \ - projectpartqueue-test.cpp \ processormanager-test.cpp \ taskscheduler-test.cpp \ compileroptionsbuilder-test.cpp \ @@ -111,7 +110,10 @@ SOURCES += \ usedmacrofilter-test.cpp \ pchtasksmerger-test.cpp \ pchtaskqueue-test.cpp \ - headerpathfilter-test.cpp + commandlinebuilder-test.cpp \ + headerpathfilter-test.cpp \ + toolchainargumentscache-test.cpp \ + modifiedtimechecker-test.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ @@ -262,7 +264,8 @@ HEADERS += \ mockbuilddependenciesstorage.h \ mockbuilddependencygenerator.h \ mockpchtasksmerger.h \ - mockpchtaskqueue.h + mockpchtaskqueue.h \ + mockpchtaskgenerator.h !isEmpty(LIBCLANG_LIBS) { HEADERS += \ diff --git a/tests/unit/unittest/usedmacrofilter-test.cpp b/tests/unit/unittest/usedmacrofilter-test.cpp index 93a29d9c9a..871d4a8535 100644 --- a/tests/unit/unittest/usedmacrofilter-test.cpp +++ b/tests/unit/unittest/usedmacrofilter-test.cpp @@ -69,6 +69,20 @@ TEST_F(UsedMacroFilter, ProjectIncludes) ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5})); } +TEST_F(UsedMacroFilter, TopSystemIncludes) +{ + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); + + ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4})); +} + +TEST_F(UsedMacroFilter, TopProjectIncludes) +{ + ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); + + ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5})); +} + TEST_F(UsedMacroFilter, SystemUsedMacros) { ClangBackEnd::UsedMacroFilter filter(includes, usedMacros); |