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>
This commit is contained in:
Marco Bubke
2018-12-17 12:06:57 +01:00
parent a78e3e5dd5
commit dd366b68de
114 changed files with 3742 additions and 1787 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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())

View File

@@ -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))

View File

@@ -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

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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);

View File

@@ -25,7 +25,7 @@
#pragma once
#include "projectpartcontainerv2.h"
#include "projectpartcontainer.h"
namespace ClangBackEnd {

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
using ProjectExplorer::HeaderPathType;
using ClangBackEnd::IncludeSearchPathType;
for (const ProjectExplorer::HeaderPath &projectPartHeaderPath : projectPartHeaderPaths) {
if (!projectPartHeaderPath.path.isEmpty())
includePaths.emplace_back(projectPartHeaderPath.path);
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 includePaths;
return IncludeSearchPathType::Invalid;
}
ClangBackEnd::V2::ProjectPartContainer ProjectUpdater::toProjectPartContainer(
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;
}
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::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(),

View File

@@ -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);

View File

@@ -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)

View File

@@ -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)

View File

@@ -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);

View File

@@ -63,6 +63,7 @@ public:
void addTargetTriple();
void addExtraCodeModelFlags();
void addPicIfCompilerFlagsContainsIt();
void addCompilerFlags();
void insertWrappedQtHeaders();
void addLanguageVersionAndExtensions();

View File

@@ -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

View File

@@ -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;

View File

@@ -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[])

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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));

View File

@@ -42,7 +42,7 @@ public:
{
}
BuildDependency create(const V2::ProjectPartContainer &projectPart) override;
BuildDependency create(const ProjectPartContainer &projectPart) override;
void collect();

View File

@@ -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;

View File

@@ -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 += \

View File

@@ -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:

View File

@@ -0,0 +1,41 @@
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <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

View File

@@ -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

View File

@@ -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>
@@ -44,41 +46,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)
bool PchCreator::generatePch()
{
QProcess process;
clang::tooling::ClangTool tool = m_clangTool.createOutputTool();
process.setProcessChannelMode(QProcess::ForwardedChannels);
process.setArguments(QStringList(compilerArguments));
process.setProgram(QString(m_environment.clangCompilerPath()));
auto action = std::make_unique<GeneratePCHActionFactory>();
process.start();
process.waitForFinished(300000);
return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
return tool.run(action.get()) != 1;
}
QStringList PchCreator::convertToQStringList(const Utils::SmallStringVector &compilerArguments)
FilePath PchCreator::generatePchHeaderFilePath() const
{
QStringList qStringList;
std::uniform_int_distribution<std::mt19937_64::result_type> distribution;
append(qStringList, compilerArguments);
return qStringList;
return FilePathView{Utils::PathString{Utils::SmallString(m_environment.pchBuildDirectory()),
"/",
std::to_string(distribution(randomNumberGenator)),
".h"}};
}
namespace {
void hashProjectPart(QCryptographicHash &hash, const V2::ProjectPartContainer &projectPart)
FilePath PchCreator::generatePchFilePath() const
{
const auto &projectPartId = projectPart.projectPartId;
hash.addData(projectPartId.data(), int(projectPartId.size()));
std::uniform_int_distribution<std::uint_fast64_t> distribution(
1, std::numeric_limits<std::uint_fast64_t>::max());
for (const auto &argument : projectPart.arguments)
hash.addData(argument.data(), int(argument.size()));
}
return FilePathView{Utils::PathString{Utils::SmallString(m_environment.pchBuildDirectory()),
"/",
std::to_string(distribution(randomNumberGenator)),
".pch"}};
}
Utils::SmallStringVector PchCreator::generateProjectPartCommandLine(
const V2::ProjectPartContainer &projectPart) const
std::vector<std::string> PchCreator::generateClangCompilerArguments(
PchTask &&pchTask,
FilePathView sourceFilePath,
FilePathView pchOutputPath)
{
const Utils::SmallStringVector &arguments = projectPart.arguments;
CommandLineBuilder<PchTask> builder{pchTask,
pchTask.toolChainArguments,
sourceFilePath,
pchOutputPath,
pchTask.systemPchPath};
Utils::SmallStringVector commandLine;
commandLine.reserve(arguments.size() + 1);
commandLine.emplace_back(m_environment.clangCompilerPath());
append(commandLine , arguments);
return commandLine;
return builder.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
{
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));
collector.addFile(filePath, projectPart.sourcePathIds, arguments);
collector.addUnsavedFiles(m_unsavedFiles);
collector.collect();
jointFile->remove();
return collector.includeIds();
}
Utils::SmallString PchCreator::generateProjectPathPchHeaderFilePath(
const V2::ProjectPartContainer &projectPart) const
{
return Utils::SmallString{generateProjectPartPchFilePathWithoutExtension(projectPart), ".h"};
}
Utils::SmallString PchCreator::generateProjectPartPchFilePath(
const V2::ProjectPartContainer &projectPart) const
{
return Utils::SmallString{generateProjectPartPchFilePathWithoutExtension(projectPart), ".pch"};
}
Utils::SmallString PchCreator::generateProjectPartSourceFilePath(const V2::ProjectPartContainer &projectPart) const
{
return Utils::SmallString{generateProjectPartPchFilePathWithoutExtension(projectPart), ".cpp"};
}
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;
}
Utils::SmallStringVector PchCreator::generateProjectPartClangCompilerArguments(
const V2::ProjectPartContainer &projectPart) const
{
Utils::SmallStringVector compilerArguments = projectPart.arguments.clone();
const auto pchArguments = generateProjectPartPchCompilerArguments(projectPart);
append(compilerArguments, pchArguments);
return compilerArguments;
}
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

View File

@@ -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)
{
}
PchManagerClientInterface &pchManagerClient)
: m_filePathCache(database)
, m_environment(environment)
, m_pchManagerClient(pchManagerClient)
{}
void generatePchDeprecated(const V2::ProjectPartContainer &projectsPart) override;
void generatePch(const PchTask &pchTask) override;
IdPaths takeProjectIncludes() override;
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);
bool generatePch();
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);
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;
};

View File

@@ -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:

View File

@@ -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*/)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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();
};
};

View File

@@ -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

View File

@@ -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;

View File

@@ -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;

View File

@@ -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:

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -56,41 +56,81 @@ public:
int64 value = -1;
};
class SourceEntry
class SourceTimeStamp
{
protected:
using int64 = long long;
public:
SourceEntry(int sourceId, int64 lastModified, int sourceType)
: lastModified(lastModified),
sourceId(sourceId),
sourceType(static_cast<SourceType>(sourceType))
SourceTimeStamp(int sourceId, int64 lastModified)
: lastModified(lastModified)
, sourceId(sourceId)
{}
SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp lastModified)
: lastModified(lastModified),
sourceId(sourceId),
sourceType(sourceType)
SourceTimeStamp(FilePathId sourceId, TimeStamp lastModified)
: lastModified(lastModified)
, sourceId(sourceId)
{}
friend
bool operator<(SourceEntry first, SourceEntry second)
friend bool operator<(SourceTimeStamp first, SourceTimeStamp second)
{
return first.sourceId < second.sourceId;
}
friend
bool operator==(SourceEntry first, SourceEntry second)
friend bool operator<(SourceTimeStamp first, FilePathId second)
{
return first.sourceId == second.sourceId
&& first.sourceType == second.sourceType
&& first.lastModified == second.lastModified ;
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)
: SourceTimeStamp(sourceId, lastModified)
, sourceType(static_cast<SourceType>(sourceType))
{}
SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp lastModified)
: SourceTimeStamp(sourceId, lastModified)
, sourceType(sourceType)
{}
friend bool operator<(SourceEntry first, SourceEntry second)
{
return first.sourceId < second.sourceId;
}
friend bool operator==(SourceEntry first, SourceEntry second)
{
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;
};

View File

@@ -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

View File

@@ -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;
};
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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");

View File

@@ -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;

View File

@@ -27,7 +27,7 @@
namespace ClangBackEnd {
void SymbolIndexing::updateProjectParts(V2::ProjectPartContainers &&projectParts)
void SymbolIndexing::updateProjectParts(ProjectPartContainers &&projectParts)
{
m_indexer.updateProjectParts(std::move(projectParts));
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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);
Utils::SmallString systemIncludeSearchPathsAsJason = toJson(systemIncludeSearchPaths);
Utils::SmallString projectIncludeSearchPathsAsJason = toJson(projectIncludeSearchPaths);
WriteStatement &insertStatement = m_insertProjectPartStatement;
insertStatement.write(projectPartName,
compilerArguementsAsJson,
compilerMacrosAsJson,
includeSearchPathsAsJason);
m_insertOrUpdateProjectPartStatement.write(projectPartName,
compilerArguementsAsJson,
compilerMacrosAsJson,
systemIncludeSearchPathsAsJason,
projectIncludeSearchPathsAsJason);
if (m_database.lastInsertedRowId() == -1) {
WriteStatement &updateStatement = m_updateProjectPartStatement;
updateStatement.write(compilerArguementsAsJson,
compilerMacrosAsJson,
includeSearchPathsAsJason,
projectPartName);
}
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 &macro : 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

View File

@@ -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:

View File

@@ -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}};

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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"

View File

@@ -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 << "("

View File

@@ -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

View File

@@ -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));
};

View File

@@ -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));
};

View File

@@ -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);
}
};

View File

@@ -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);
}
};

View File

@@ -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);
}
};

View File

@@ -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));
};

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -144,16 +144,23 @@ MockSqliteReadStatement::value<Utils::PathString>(const Utils::SmallStringView &
return valueReturnPathString(path);
}
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);
}

View File

@@ -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));
@@ -212,6 +215,10 @@ template <>
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>

View File

@@ -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));

View File

@@ -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);
}

View File

@@ -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));

View File

@@ -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

View File

@@ -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);
auto arguments = creator.generateClangCompilerArguments(std::move(pchTask1),
"project.h",
"project.pch");
ASSERT_THAT(arguments, AllOf(Contains(TESTDATA_DIR),
Contains("-emit-pch"),
Contains("-o"),
Not(Contains(environment.clangCompilerPath()))));
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(PchCreatorVerySlowTest, IncludesForCreatePchsForProjectParts)
TEST_F(PchCreator, CreateProjectPartClangCompilerArgumentsWithSystemPch)
{
creator.generatePchDeprecated(projectPart1);
pchTask1.systemPchPath = "system.pch";
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",
"-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)
TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForPchTask)
{
creator.generatePchDeprecated(projectPart1);
EXPECT_CALL(mockClangPathWatcher,
updateIdPaths(ElementsAre(creator.projectIncludes())));
creator.doInMainThreadAfterFinished();
}
TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts)
{
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)
TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesFaultyPchForPchTask)
{
creator.generatePchDeprecated(projectPart1);
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.clear();
ASSERT_THAT(creator.projectIncludes(), ClangBackEnd::IdPaths{});
}
TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesNoPchForProjectPart)
{
ProjectPartContainer faultyProjectPart{"faultyProject",
{"-I", TESTDATA_DIR},
{{"DEFINE", "1", 1}},
{"/includes"},
{},
{id(TESTDATA_DIR "/builddependencycollector/project/faulty.cpp")}};
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"));
}
}

View File

@@ -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}}};
};

View File

@@ -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));

View File

@@ -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});
}
}

View File

@@ -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(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,
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.create({projectPart1});
generator.addProjectParts({projectPart1}, {"ToolChainArgument"});
}
TEST_F(PchTaskGenerator, RemoveProjectParts)
{
ON_CALL(mockBuildDependenciesProvider, create(_)).WillByDefault(Return(buildDependency));
EXPECT_CALL(
mockPchTaskMerger,
removePchTasks(ElementsAre("project1", "project2")));
generator.removeProjectParts({"project1", "project2"});
}
}

View File

@@ -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);
}

View File

@@ -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"});
}
}

View File

@@ -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");

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);
}
}

Some files were not shown because too many files have changed in this diff Show More