forked from qt-creator/qt-creator
Merge remote-tracking branch 'origin/5.0'
Change-Id: Ia018600fb257c9523fc9d15faa5bd8300840e3de
This commit is contained in:
@@ -130,11 +130,26 @@ QString ClangDiagnosticConfig::clangTidyChecksAsJson() const
|
||||
{
|
||||
QString jsonString = "{Checks: '" + clangTidyChecks()
|
||||
+ ",-clang-diagnostic-*', CheckOptions: [";
|
||||
|
||||
// The check is either listed verbatim or covered by the "<prefix>-*" pattern.
|
||||
const auto checkIsEnabled = [this](const QString &check) {
|
||||
for (QString subString = check; !subString.isEmpty();
|
||||
subString.chop(subString.length() - subString.lastIndexOf('-'))) {
|
||||
const int idx = m_clangTidyChecks.indexOf(subString);
|
||||
if (idx == -1)
|
||||
continue;
|
||||
if (idx > 0 && m_clangTidyChecks.at(idx - 1) == '-')
|
||||
continue;
|
||||
if (subString == check || QStringView(m_clangTidyChecks)
|
||||
.mid(idx + subString.length()).startsWith(QLatin1String("-*"))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
for (auto it = m_tidyChecksOptions.cbegin(); it != m_tidyChecksOptions.cend(); ++it) {
|
||||
const int idx = m_clangTidyChecks.indexOf(it.key());
|
||||
if (idx == -1)
|
||||
continue;
|
||||
if (idx > 0 && m_clangTidyChecks.at(idx - 1) == '-')
|
||||
if (!checkIsEnabled(it.key()))
|
||||
continue;
|
||||
QString optionString;
|
||||
for (auto optIt = it.value().begin(); optIt != it.value().end(); ++optIt) {
|
||||
|
||||
@@ -165,6 +165,11 @@ void CompilerOptionsBuilder::add(const QString &arg, bool gccOnlyOption)
|
||||
add(QStringList{arg}, gccOnlyOption);
|
||||
}
|
||||
|
||||
void CompilerOptionsBuilder::prepend(const QString &arg)
|
||||
{
|
||||
m_options.prepend(arg);
|
||||
}
|
||||
|
||||
void CompilerOptionsBuilder::add(const QStringList &args, bool gccOnlyOptions)
|
||||
{
|
||||
m_options.append((gccOnlyOptions && isClStyle()) ? clangArgsForCl(args) : args);
|
||||
|
||||
@@ -85,6 +85,7 @@ public:
|
||||
|
||||
// Add custom options
|
||||
void add(const QString &arg, bool gccOnlyOption = false);
|
||||
void prepend(const QString &arg);
|
||||
void add(const QStringList &args, bool gccOnlyOptions = false);
|
||||
virtual void addExtraOptions() {}
|
||||
|
||||
|
||||
@@ -29,6 +29,9 @@
|
||||
#include "cpptoolsconstants.h"
|
||||
#include "cpptoolsreuse.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <projectexplorer/project.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
@@ -61,8 +64,12 @@ static QString skipIndexingBigFilesKey()
|
||||
static QString indexerFileSizeLimitKey()
|
||||
{ return QLatin1String(Constants::CPPTOOLS_INDEXER_FILE_SIZE_LIMIT); }
|
||||
|
||||
static QString clangdSettingsKey() { return QLatin1String("ClangdSettings"); }
|
||||
static QString useClangdKey() { return QLatin1String("UseClangd"); }
|
||||
static QString clangdPathKey() { return QLatin1String("ClangdPath"); }
|
||||
static QString clangdIndexingKey() { return QLatin1String("ClangdIndexing"); }
|
||||
static QString clangdThreadLimitKey() { return QLatin1String("ClangdThreadLimit"); }
|
||||
static QString clangdUseGlobalSettingsKey() { return QLatin1String("useGlobalSettings"); }
|
||||
|
||||
static FilePath g_defaultClangdFilePath;
|
||||
static FilePath fallbackClangdFilePath()
|
||||
@@ -172,9 +179,6 @@ void CppCodeModelSettings::fromSettings(QSettings *s)
|
||||
const QVariant indexerFileSizeLimit = s->value(indexerFileSizeLimitKey(), 5);
|
||||
setIndexerFileSizeLimitInMb(indexerFileSizeLimit.toInt());
|
||||
|
||||
setUseClangd(s->value(useClangdKey(), false).toBool());
|
||||
setClangdFilePath(FilePath::fromString(s->value(clangdPathKey()).toString()));
|
||||
|
||||
s->endGroup();
|
||||
|
||||
if (write)
|
||||
@@ -198,8 +202,6 @@ void CppCodeModelSettings::toSettings(QSettings *s)
|
||||
s->setValue(interpretAmbiguousHeadersAsCHeadersKey(), interpretAmbigiousHeadersAsCHeaders());
|
||||
s->setValue(skipIndexingBigFilesKey(), skipIndexingBigFiles());
|
||||
s->setValue(indexerFileSizeLimitKey(), indexerFileSizeLimitInMb());
|
||||
s->setValue(useClangdKey(), useClangd());
|
||||
s->setValue(clangdPathKey(), m_clangdFilePath.toString());
|
||||
|
||||
s->endGroup();
|
||||
|
||||
@@ -300,14 +302,113 @@ void CppCodeModelSettings::setEnableLowerClazyLevels(bool yesno)
|
||||
m_enableLowerClazyLevels = yesno;
|
||||
}
|
||||
|
||||
void CppCodeModelSettings::setDefaultClangdPath(const Utils::FilePath &filePath)
|
||||
|
||||
ClangdSettings &ClangdSettings::instance()
|
||||
{
|
||||
static ClangdSettings settings;
|
||||
return settings;
|
||||
}
|
||||
|
||||
void ClangdSettings::setDefaultClangdPath(const Utils::FilePath &filePath)
|
||||
{
|
||||
g_defaultClangdFilePath = filePath;
|
||||
}
|
||||
|
||||
FilePath CppCodeModelSettings::clangdFilePath() const
|
||||
FilePath ClangdSettings::clangdFilePath() const
|
||||
{
|
||||
if (!m_clangdFilePath.isEmpty())
|
||||
return m_clangdFilePath;
|
||||
if (!m_data.executableFilePath.isEmpty())
|
||||
return m_data.executableFilePath;
|
||||
return fallbackClangdFilePath();
|
||||
}
|
||||
|
||||
void ClangdSettings::setData(const Data &data)
|
||||
{
|
||||
if (this == &instance() && data != m_data) {
|
||||
m_data = data;
|
||||
saveSettings();
|
||||
emit changed();
|
||||
}
|
||||
}
|
||||
|
||||
void ClangdSettings::loadSettings()
|
||||
{
|
||||
m_data.fromMap(Core::ICore::settings()->value(clangdSettingsKey()).toMap());
|
||||
}
|
||||
|
||||
void ClangdSettings::saveSettings()
|
||||
{
|
||||
Core::ICore::settings()->setValue(clangdSettingsKey(), m_data.toMap());
|
||||
}
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
void ClangdSettings::setUseClangd(bool use) { instance().m_data.useClangd = use; }
|
||||
void ClangdSettings::setClangdFilePath(const Utils::FilePath &filePath)
|
||||
{
|
||||
instance().m_data.executableFilePath = filePath;
|
||||
}
|
||||
#endif
|
||||
|
||||
ClangdProjectSettings::ClangdProjectSettings(ProjectExplorer::Project *project) : m_project(project)
|
||||
{
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
ClangdSettings::Data ClangdProjectSettings::settings() const
|
||||
{
|
||||
if (m_useGlobalSettings)
|
||||
return ClangdSettings::instance().data();
|
||||
return m_customSettings;
|
||||
}
|
||||
|
||||
void ClangdProjectSettings::setSettings(const ClangdSettings::Data &data)
|
||||
{
|
||||
m_customSettings = data;
|
||||
saveSettings();
|
||||
emit ClangdSettings::instance().changed();
|
||||
}
|
||||
|
||||
void ClangdProjectSettings::setUseGlobalSettings(bool useGlobal)
|
||||
{
|
||||
m_useGlobalSettings = useGlobal;
|
||||
saveSettings();
|
||||
emit ClangdSettings::instance().changed();
|
||||
}
|
||||
|
||||
void ClangdProjectSettings::loadSettings()
|
||||
{
|
||||
if (!m_project)
|
||||
return;
|
||||
const QVariantMap data = m_project->namedSettings(clangdSettingsKey()).toMap();
|
||||
m_useGlobalSettings = data.value(clangdUseGlobalSettingsKey(), true).toBool();
|
||||
if (!m_useGlobalSettings)
|
||||
m_customSettings.fromMap(data);
|
||||
}
|
||||
|
||||
void ClangdProjectSettings::saveSettings()
|
||||
{
|
||||
if (!m_project)
|
||||
return;
|
||||
QVariantMap data;
|
||||
if (!m_useGlobalSettings)
|
||||
data = m_customSettings.toMap();
|
||||
data.insert(clangdUseGlobalSettingsKey(), m_useGlobalSettings);
|
||||
m_project->setNamedSettings(clangdSettingsKey(), data);
|
||||
}
|
||||
|
||||
QVariantMap ClangdSettings::Data::toMap() const
|
||||
{
|
||||
QVariantMap map;
|
||||
map.insert(useClangdKey(), useClangd);
|
||||
map.insert(clangdPathKey(), executableFilePath.toString());
|
||||
map.insert(clangdIndexingKey(), enableIndexing);
|
||||
map.insert(clangdThreadLimitKey(), workerThreadLimit);
|
||||
return map;
|
||||
}
|
||||
|
||||
void ClangdSettings::Data::fromMap(const QVariantMap &map)
|
||||
{
|
||||
useClangd = map.value(useClangdKey(), false).toBool();
|
||||
executableFilePath = FilePath::fromString(map.value(clangdPathKey()).toString());
|
||||
enableIndexing = map.value(clangdIndexingKey(), true).toBool();
|
||||
workerThreadLimit = map.value(clangdThreadLimitKey(), 0).toInt();
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ QT_BEGIN_NAMESPACE
|
||||
class QSettings;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace ProjectExplorer { class Project; }
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
class CPPTOOLS_EXPORT CppCodeModelSettings : public QObject
|
||||
@@ -78,13 +80,6 @@ public:
|
||||
int indexerFileSizeLimitInMb() const;
|
||||
void setIndexerFileSizeLimitInMb(int sizeInMB);
|
||||
|
||||
void setUseClangd(bool use) { m_useClangd = use; }
|
||||
bool useClangd() const { return m_useClangd; }
|
||||
|
||||
static void setDefaultClangdPath(const Utils::FilePath &filePath);
|
||||
void setClangdFilePath(const Utils::FilePath &filePath) { m_clangdFilePath = filePath; }
|
||||
Utils::FilePath clangdFilePath() const;
|
||||
|
||||
void setCategorizeFindReferences(bool categorize) { m_categorizeFindReferences = categorize; }
|
||||
bool categorizeFindReferences() const { return m_categorizeFindReferences; }
|
||||
|
||||
@@ -100,9 +95,84 @@ private:
|
||||
ClangDiagnosticConfigs m_clangCustomDiagnosticConfigs;
|
||||
Utils::Id m_clangDiagnosticConfigId;
|
||||
bool m_enableLowerClazyLevels = true; // For UI behavior only
|
||||
Utils::FilePath m_clangdFilePath;
|
||||
bool m_useClangd = false;
|
||||
bool m_categorizeFindReferences = false; // Ephemeral!
|
||||
};
|
||||
|
||||
class CPPTOOLS_EXPORT ClangdSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class CPPTOOLS_EXPORT Data
|
||||
{
|
||||
public:
|
||||
QVariantMap toMap() const;
|
||||
void fromMap(const QVariantMap &map);
|
||||
|
||||
Utils::FilePath executableFilePath;
|
||||
int workerThreadLimit = 0;
|
||||
bool useClangd = false;
|
||||
bool enableIndexing = true;
|
||||
};
|
||||
|
||||
ClangdSettings(const Data &data) : m_data(data) {}
|
||||
|
||||
static ClangdSettings &instance();
|
||||
bool useClangd() const { return m_data.useClangd; }
|
||||
|
||||
static void setDefaultClangdPath(const Utils::FilePath &filePath);
|
||||
Utils::FilePath clangdFilePath() const;
|
||||
bool indexingEnabled() const { return m_data.enableIndexing; }
|
||||
int workerThreadLimit() const { return m_data.workerThreadLimit; }
|
||||
|
||||
void setData(const Data &data);
|
||||
Data data() const { return m_data; }
|
||||
|
||||
#ifdef WITH_TESTS
|
||||
static void setUseClangd(bool use);
|
||||
static void setClangdFilePath(const Utils::FilePath &filePath);
|
||||
#endif
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
|
||||
private:
|
||||
ClangdSettings() { loadSettings(); }
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
Data m_data;
|
||||
};
|
||||
|
||||
inline bool operator==(const ClangdSettings::Data &s1, const ClangdSettings::Data &s2)
|
||||
{
|
||||
return s1.useClangd == s2.useClangd
|
||||
&& s1.executableFilePath == s2.executableFilePath
|
||||
&& s1.workerThreadLimit == s2.workerThreadLimit
|
||||
&& s1.enableIndexing == s2.enableIndexing;
|
||||
}
|
||||
inline bool operator!=(const ClangdSettings::Data &s1, const ClangdSettings::Data &s2)
|
||||
{
|
||||
return !(s1 == s2);
|
||||
}
|
||||
|
||||
class CPPTOOLS_EXPORT ClangdProjectSettings
|
||||
{
|
||||
public:
|
||||
ClangdProjectSettings(ProjectExplorer::Project *project);
|
||||
|
||||
ClangdSettings::Data settings() const;
|
||||
void setSettings(const ClangdSettings::Data &data);
|
||||
bool useGlobalSettings() const { return m_useGlobalSettings; }
|
||||
void setUseGlobalSettings(bool useGlobal);
|
||||
|
||||
private:
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
|
||||
ProjectExplorer::Project * const m_project;
|
||||
ClangdSettings::Data m_customSettings;
|
||||
bool m_useGlobalSettings = true;
|
||||
};
|
||||
|
||||
} // namespace CppTools
|
||||
|
||||
@@ -33,7 +33,10 @@
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/pathchooser.h>
|
||||
|
||||
#include <QFormLayout>
|
||||
#include <QSpinBox>
|
||||
#include <QTextStream>
|
||||
|
||||
namespace CppTools {
|
||||
@@ -100,8 +103,6 @@ void CppCodeModelSettingsWidget::setupClangCodeModelWidgets()
|
||||
const bool isClangActive = CppModelManager::instance()->isClangCodeModelActive();
|
||||
m_ui->clangCodeModelIsDisabledHint->setVisible(!isClangActive);
|
||||
m_ui->clangCodeModelIsEnabledHint->setVisible(isClangActive);
|
||||
m_ui->clangdCheckBox->setVisible(isClangActive);
|
||||
m_ui->clangdChooser->setVisible(isClangActive);
|
||||
|
||||
for (int i = 0; i < m_ui->clangDiagnosticConfigsSelectionWidget->layout()->count(); ++i) {
|
||||
QWidget *widget = m_ui->clangDiagnosticConfigsSelectionWidget->layout()->itemAt(i)->widget();
|
||||
@@ -120,16 +121,6 @@ void CppCodeModelSettingsWidget::setupGeneralWidgets()
|
||||
|
||||
const bool ignorePch = m_settings->pchUsage() == CppCodeModelSettings::PchUse_None;
|
||||
m_ui->ignorePCHCheckBox->setChecked(ignorePch);
|
||||
|
||||
m_ui->clangdCheckBox->setChecked(m_settings->useClangd());
|
||||
m_ui->clangdCheckBox->setToolTip(tr("Use clangd for locators and \"Find References\".\n"
|
||||
"Changing this option does not affect projects that are already open."));
|
||||
m_ui->clangdChooser->setExpectedKind(Utils::PathChooser::ExistingCommand);
|
||||
m_ui->clangdChooser->setFilePath(codeModelSettings()->clangdFilePath());
|
||||
m_ui->clangdChooser->setEnabled(m_ui->clangdCheckBox->isChecked());
|
||||
connect(m_ui->clangdCheckBox, &QCheckBox::toggled, m_ui->clangdChooser, [this](bool checked) {
|
||||
m_ui->clangdChooser->setEnabled(checked);
|
||||
});
|
||||
}
|
||||
|
||||
bool CppCodeModelSettingsWidget::applyClangCodeModelWidgetsToSettings() const
|
||||
@@ -176,16 +167,6 @@ bool CppCodeModelSettingsWidget::applyGeneralWidgetsToSettings() const
|
||||
m_settings->setIndexerFileSizeLimitInMb(newFileSizeLimit);
|
||||
settingsChanged = true;
|
||||
}
|
||||
const bool newUseClangd = m_ui->clangdCheckBox->isChecked();
|
||||
if (m_settings->useClangd() != newUseClangd) {
|
||||
m_settings->setUseClangd(newUseClangd);
|
||||
settingsChanged = true;
|
||||
}
|
||||
const Utils::FilePath newClangdPath = m_ui->clangdChooser->rawFilePath();
|
||||
if (m_settings->clangdFilePath() != newClangdPath) {
|
||||
m_settings->setClangdFilePath(newClangdPath);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
const bool newIgnorePch = m_ui->ignorePCHCheckBox->isChecked();
|
||||
const bool previousIgnorePch = m_settings->pchUsage() == CppCodeModelSettings::PchUse_None;
|
||||
@@ -210,5 +191,147 @@ CppCodeModelSettingsPage::CppCodeModelSettingsPage(CppCodeModelSettings *setting
|
||||
setWidgetCreator([settings] { return new CppCodeModelSettingsWidget(settings); });
|
||||
}
|
||||
|
||||
class ClangdSettingsWidget::Private
|
||||
{
|
||||
public:
|
||||
QCheckBox useClangdCheckBox;
|
||||
QCheckBox indexingCheckBox;
|
||||
QSpinBox threadLimitSpinBox;
|
||||
Utils::PathChooser clangdChooser;
|
||||
};
|
||||
|
||||
ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsData)
|
||||
: d(new Private)
|
||||
{
|
||||
const ClangdSettings settings(settingsData);
|
||||
d->useClangdCheckBox.setText(tr("Use clangd (EXPERIMENTAL)"));
|
||||
d->useClangdCheckBox.setChecked(settings.useClangd());
|
||||
d->clangdChooser.setExpectedKind(Utils::PathChooser::ExistingCommand);
|
||||
d->clangdChooser.setFilePath(settings.clangdFilePath());
|
||||
d->clangdChooser.setEnabled(d->useClangdCheckBox.isChecked());
|
||||
d->indexingCheckBox.setChecked(settings.indexingEnabled());
|
||||
d->indexingCheckBox.setToolTip(tr(
|
||||
"If background indexing is enabled, global symbol searches will yield\n"
|
||||
"more accurate results, at the cost of additional CPU load when\n"
|
||||
"the project is first opened."));
|
||||
d->threadLimitSpinBox.setValue(settings.workerThreadLimit());
|
||||
d->threadLimitSpinBox.setSpecialValueText("Automatic");
|
||||
|
||||
const auto layout = new QVBoxLayout(this);
|
||||
layout->addWidget(&d->useClangdCheckBox);
|
||||
const auto formLayout = new QFormLayout;
|
||||
const auto chooserLabel = new QLabel(tr("Path to executable:"));
|
||||
formLayout->addRow(chooserLabel, &d->clangdChooser);
|
||||
const auto indexingLabel = new QLabel(tr("Enable background indexing:"));
|
||||
formLayout->addRow(indexingLabel, &d->indexingCheckBox);
|
||||
const auto threadLimitLayout = new QHBoxLayout;
|
||||
threadLimitLayout->addWidget(&d->threadLimitSpinBox);
|
||||
threadLimitLayout->addStretch(1);
|
||||
const auto threadLimitLabel = new QLabel(tr("Set worker thread count:"));
|
||||
formLayout->addRow(threadLimitLabel, threadLimitLayout);
|
||||
layout->addLayout(formLayout);
|
||||
layout->addStretch(1);
|
||||
|
||||
const auto toggleEnabled = [=](const bool checked) {
|
||||
chooserLabel->setEnabled(checked);
|
||||
d->clangdChooser.setEnabled(checked);
|
||||
indexingLabel->setEnabled(checked);
|
||||
d->indexingCheckBox.setEnabled(checked);
|
||||
d->threadLimitSpinBox.setEnabled(checked);
|
||||
};
|
||||
connect(&d->useClangdCheckBox, &QCheckBox::toggled, toggleEnabled);
|
||||
toggleEnabled(d->useClangdCheckBox.isChecked());
|
||||
d->threadLimitSpinBox.setEnabled(d->useClangdCheckBox.isChecked());
|
||||
|
||||
connect(&d->useClangdCheckBox, &QCheckBox::toggled,
|
||||
this, &ClangdSettingsWidget::settingsDataChanged);
|
||||
connect(&d->indexingCheckBox, &QCheckBox::toggled,
|
||||
this, &ClangdSettingsWidget::settingsDataChanged);
|
||||
connect(&d->threadLimitSpinBox, qOverload<int>(&QSpinBox::valueChanged),
|
||||
this, &ClangdSettingsWidget::settingsDataChanged);
|
||||
connect(&d->clangdChooser, &Utils::PathChooser::pathChanged,
|
||||
this, &ClangdSettingsWidget::settingsDataChanged);
|
||||
}
|
||||
|
||||
ClangdSettingsWidget::~ClangdSettingsWidget()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
ClangdSettings::Data ClangdSettingsWidget::settingsData() const
|
||||
{
|
||||
ClangdSettings::Data data;
|
||||
data.useClangd = d->useClangdCheckBox.isChecked();
|
||||
data.executableFilePath = d->clangdChooser.filePath();
|
||||
data.enableIndexing = d->indexingCheckBox.isChecked();
|
||||
data.workerThreadLimit = d->threadLimitSpinBox.value();
|
||||
return data;
|
||||
}
|
||||
|
||||
class ClangdSettingsPageWidget final : public Core::IOptionsPageWidget
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(CppTools::Internal::ClangdSettingsWidget)
|
||||
|
||||
public:
|
||||
ClangdSettingsPageWidget() : m_widget(ClangdSettings::instance().data())
|
||||
{
|
||||
const auto layout = new QVBoxLayout(this);
|
||||
layout->addWidget(&m_widget);
|
||||
}
|
||||
|
||||
private:
|
||||
void apply() final { ClangdSettings::instance().setData(m_widget.settingsData()); }
|
||||
|
||||
ClangdSettingsWidget m_widget;
|
||||
};
|
||||
|
||||
ClangdSettingsPage::ClangdSettingsPage()
|
||||
{
|
||||
setId("K.Clangd");
|
||||
setDisplayName(ClangdSettingsWidget::tr("Clangd"));
|
||||
setCategory(Constants::CPP_SETTINGS_CATEGORY);
|
||||
setWidgetCreator([] { return new ClangdSettingsPageWidget; });
|
||||
}
|
||||
|
||||
|
||||
class ClangdProjectSettingsWidget::Private
|
||||
{
|
||||
public:
|
||||
Private(const ClangdProjectSettings &s) : settings(s), widget(s.settings()) {}
|
||||
|
||||
ClangdProjectSettings settings;
|
||||
ClangdSettingsWidget widget;
|
||||
QCheckBox useGlobalSettingsCheckBox;
|
||||
};
|
||||
|
||||
ClangdProjectSettingsWidget::ClangdProjectSettingsWidget(const ClangdProjectSettings &settings)
|
||||
: d(new Private(settings))
|
||||
{
|
||||
const auto layout = new QVBoxLayout(this);
|
||||
d->useGlobalSettingsCheckBox.setText(tr("Use global settings"));
|
||||
layout->addWidget(&d->useGlobalSettingsCheckBox);
|
||||
const auto separator = new QFrame;
|
||||
separator->setFrameShape(QFrame::HLine);
|
||||
layout->addWidget(separator);
|
||||
layout->addWidget(&d->widget);
|
||||
|
||||
d->useGlobalSettingsCheckBox.setChecked(d->settings.useGlobalSettings());
|
||||
d->widget.setEnabled(!d->settings.useGlobalSettings());
|
||||
connect(&d->useGlobalSettingsCheckBox, &QCheckBox::toggled, [this](bool checked) {
|
||||
d->widget.setEnabled(!checked);
|
||||
d->settings.setUseGlobalSettings(checked);
|
||||
if (!checked)
|
||||
d->settings.setSettings(d->widget.settingsData());
|
||||
});
|
||||
connect(&d->widget, &ClangdSettingsWidget::settingsDataChanged, [this] {
|
||||
d->settings.setSettings(d->widget.settingsData());
|
||||
});
|
||||
}
|
||||
|
||||
ClangdProjectSettingsWidget::~ClangdProjectSettingsWidget()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
} // Internal
|
||||
} // CppTools
|
||||
|
||||
@@ -38,5 +38,42 @@ public:
|
||||
explicit CppCodeModelSettingsPage(CppCodeModelSettings *settings);
|
||||
};
|
||||
|
||||
class ClangdSettingsPage final : public Core::IOptionsPage
|
||||
{
|
||||
public:
|
||||
explicit ClangdSettingsPage();
|
||||
};
|
||||
|
||||
class ClangdSettingsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClangdSettingsWidget(const ClangdSettings::Data &settingsData);
|
||||
~ClangdSettingsWidget();
|
||||
|
||||
ClangdSettings::Data settingsData() const;
|
||||
|
||||
signals:
|
||||
void settingsDataChanged();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
class ClangdProjectSettingsWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ClangdProjectSettingsWidget(const ClangdProjectSettings &settings);
|
||||
~ClangdProjectSettingsWidget();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private * const d;
|
||||
};
|
||||
|
||||
} // Internal namespace
|
||||
} // CppTools namespace
|
||||
|
||||
@@ -81,31 +81,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="clangdCheckBox">
|
||||
<property name="text">
|
||||
<string>Use clangd (EXPERIMENTAL)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Utils::PathChooser" name="clangdChooser"/>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -174,11 +150,6 @@
|
||||
<extends>QWidget</extends>
|
||||
<header>cpptools/clangdiagnosticconfigsselectionwidget.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Utils::PathChooser</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header location="global">utils/pathchooser.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -100,7 +100,7 @@ void CppToolsPlugin::initTestCase()
|
||||
|
||||
void CppToolsPlugin::cleanupTestCase()
|
||||
{
|
||||
Utils::FileUtils::removeRecursively(Utils::FilePath::fromString(baseTestDir()));
|
||||
Utils::FilePath::fromString(baseTestDir()).removeRecursively();
|
||||
CppFileSettings *fs = fileSettings();
|
||||
fs->headerSearchPaths.removeLast();
|
||||
fs->headerSearchPaths.removeLast();
|
||||
|
||||
@@ -1145,7 +1145,8 @@ void CppModelManager::updateCppEditorDocuments(bool projectsUpdated) const
|
||||
}
|
||||
}
|
||||
|
||||
QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &newProjectInfo)
|
||||
QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &newProjectInfo,
|
||||
const QSet<QString> &additionalFiles)
|
||||
{
|
||||
if (!newProjectInfo.isValid())
|
||||
return QFuture<void>();
|
||||
@@ -1236,6 +1237,7 @@ QFuture<void> CppModelManager::updateProjectInfo(const ProjectInfo &newProjectIn
|
||||
// resolved includes that we could rely on.
|
||||
updateCppEditorDocuments(/*projectsUpdated = */ true);
|
||||
|
||||
filesToReindex.unite(additionalFiles);
|
||||
// Trigger reindexing
|
||||
const QFuture<void> indexingFuture = updateSourceFiles(filesToReindex,
|
||||
ForcedProgressNotification);
|
||||
@@ -1310,6 +1312,11 @@ bool CppModelManager::isCppEditor(Core::IEditor *editor)
|
||||
return editor->context().contains(ProjectExplorer::Constants::CXX_LANGUAGE_ID);
|
||||
}
|
||||
|
||||
bool CppModelManager::supportsOutline(const TextEditor::TextDocument *document)
|
||||
{
|
||||
return instance()->d->m_activeModelManagerSupport->supportsOutline(document);
|
||||
}
|
||||
|
||||
bool CppModelManager::isClangCodeModelActive() const
|
||||
{
|
||||
return d->m_activeModelManagerSupport != d->m_builtinModelManagerSupport;
|
||||
|
||||
@@ -116,7 +116,8 @@ public:
|
||||
|
||||
QList<ProjectInfo> projectInfos() const;
|
||||
ProjectInfo projectInfo(ProjectExplorer::Project *project) const;
|
||||
QFuture<void> updateProjectInfo(const ProjectInfo &newProjectInfo);
|
||||
QFuture<void> updateProjectInfo(const ProjectInfo &newProjectInfo,
|
||||
const QSet<QString> &additionalFiles = {});
|
||||
|
||||
/// \return The project part with the given project file
|
||||
ProjectPart::Ptr projectPartForId(const QString &projectPartId) const override;
|
||||
@@ -142,6 +143,7 @@ public:
|
||||
void emitAbstractEditorSupportRemoved(const QString &filePath);
|
||||
|
||||
static bool isCppEditor(Core::IEditor *editor);
|
||||
static bool supportsOutline(const TextEditor::TextDocument *document);
|
||||
bool isClangCodeModelActive() const;
|
||||
|
||||
QSet<AbstractEditorSupport*> abstractEditorSupports() const;
|
||||
|
||||
@@ -61,6 +61,7 @@ public:
|
||||
virtual FollowSymbolInterface &followSymbolInterface() = 0;
|
||||
virtual RefactoringEngineInterface &refactoringEngineInterface() = 0;
|
||||
virtual std::unique_ptr<AbstractOverviewModel> createOverviewModel() = 0;
|
||||
virtual bool supportsOutline(const TextEditor::TextDocument *) const { return true; }
|
||||
};
|
||||
|
||||
class CPPTOOLS_EXPORT ModelManagerSupportProvider
|
||||
|
||||
@@ -27,14 +27,21 @@
|
||||
|
||||
#include "cppmodelmanager.h"
|
||||
#include "cppprojectinfogenerator.h"
|
||||
#include "generatedcodemodelsupport.h"
|
||||
|
||||
#include <coreplugin/progressmanager/progressmanager.h>
|
||||
|
||||
#include <projectexplorer/toolchainmanager.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/runextensions.h>
|
||||
|
||||
#include <QFutureInterface>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace CppTools {
|
||||
|
||||
CppProjectUpdater::CppProjectUpdater()
|
||||
@@ -46,11 +53,25 @@ CppProjectUpdater::CppProjectUpdater()
|
||||
m_futureSynchronizer.setCancelOnWait(true);
|
||||
}
|
||||
|
||||
void CppProjectUpdater::update(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo)
|
||||
CppProjectUpdater::~CppProjectUpdater()
|
||||
{
|
||||
cancel();
|
||||
}
|
||||
|
||||
void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo)
|
||||
{
|
||||
update(projectUpdateInfo, {});
|
||||
}
|
||||
|
||||
void CppProjectUpdater::update(const ProjectUpdateInfo &projectUpdateInfo,
|
||||
const QList<ProjectExplorer::ExtraCompiler *> &extraCompilers)
|
||||
{
|
||||
// Stop previous update.
|
||||
cancel();
|
||||
|
||||
m_extraCompilers = Utils::transform(extraCompilers, [](ExtraCompiler *compiler) {
|
||||
return QPointer<ExtraCompiler>(compiler);
|
||||
});
|
||||
m_projectUpdateInfo = projectUpdateInfo;
|
||||
|
||||
// Ensure that we do not operate on a deleted toolchain.
|
||||
@@ -68,15 +89,52 @@ void CppProjectUpdater::update(const ProjectExplorer::ProjectUpdateInfo &project
|
||||
});
|
||||
m_generateFutureWatcher.setFuture(generateFuture);
|
||||
m_futureSynchronizer.addFuture(generateFuture);
|
||||
|
||||
// extra compilers
|
||||
for (QPointer<ExtraCompiler> compiler : qAsConst(m_extraCompilers)) {
|
||||
if (compiler->isDirty()) {
|
||||
auto watcher = new QFutureWatcher<void>;
|
||||
// queued connection to delay after the extra compiler updated its result contents,
|
||||
// which is also done in the main thread when compiler->run() finished
|
||||
connect(watcher, &QFutureWatcherBase::finished,
|
||||
this, [this, watcher] {
|
||||
m_projectUpdateFutureInterface->setProgressValue(
|
||||
m_projectUpdateFutureInterface->progressValue() + 1);
|
||||
m_extraCompilersFutureWatchers.remove(watcher);
|
||||
watcher->deleteLater();
|
||||
if (!watcher->isCanceled())
|
||||
checkForExtraCompilersFinished();
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
m_extraCompilersFutureWatchers += watcher;
|
||||
watcher->setFuture(QFuture<void>(compiler->run()));
|
||||
m_futureSynchronizer.addFuture(watcher->future());
|
||||
}
|
||||
}
|
||||
|
||||
m_projectUpdateFutureInterface.reset(new QFutureInterface<void>);
|
||||
m_projectUpdateFutureInterface->setProgressRange(0, m_extraCompilersFutureWatchers.size()
|
||||
+ 1 /*generateFuture*/);
|
||||
m_projectUpdateFutureInterface->setProgressValue(0);
|
||||
m_projectUpdateFutureInterface->reportStarted();
|
||||
Core::ProgressManager::addTask(m_projectUpdateFutureInterface->future(),
|
||||
tr("Preparing C++ Code Model"),
|
||||
"CppProjectUpdater");
|
||||
}
|
||||
|
||||
void CppProjectUpdater::cancel()
|
||||
{
|
||||
if (m_projectUpdateFutureInterface && m_projectUpdateFutureInterface->isRunning())
|
||||
m_projectUpdateFutureInterface->reportFinished();
|
||||
m_generateFutureWatcher.setFuture({});
|
||||
m_isProjectInfoGenerated = false;
|
||||
qDeleteAll(m_extraCompilersFutureWatchers);
|
||||
m_extraCompilersFutureWatchers.clear();
|
||||
m_extraCompilers.clear();
|
||||
m_futureSynchronizer.cancelAllFutures();
|
||||
}
|
||||
|
||||
void CppProjectUpdater::onToolChainRemoved(ProjectExplorer::ToolChain *t)
|
||||
void CppProjectUpdater::onToolChainRemoved(ToolChain *t)
|
||||
{
|
||||
QTC_ASSERT(t, return);
|
||||
if (t == m_projectUpdateInfo.cToolChain || t == m_projectUpdateInfo.cxxToolChain)
|
||||
@@ -93,8 +151,33 @@ void CppProjectUpdater::onProjectInfoGenerated()
|
||||
if (m_generateFutureWatcher.isCanceled() || m_generateFutureWatcher.future().resultCount() < 1)
|
||||
return;
|
||||
|
||||
auto updateFuture = CppModelManager::instance()->updateProjectInfo(
|
||||
m_generateFutureWatcher.result());
|
||||
m_projectUpdateFutureInterface->setProgressValue(m_projectUpdateFutureInterface->progressValue()
|
||||
+ 1);
|
||||
m_isProjectInfoGenerated = true;
|
||||
checkForExtraCompilersFinished();
|
||||
}
|
||||
|
||||
void CppProjectUpdater::checkForExtraCompilersFinished()
|
||||
{
|
||||
if (!m_extraCompilersFutureWatchers.isEmpty() || !m_isProjectInfoGenerated)
|
||||
return; // still need to wait
|
||||
|
||||
m_projectUpdateFutureInterface->reportFinished();
|
||||
m_projectUpdateFutureInterface.reset();
|
||||
|
||||
QList<ExtraCompiler *> extraCompilers;
|
||||
QSet<QString> compilerFiles;
|
||||
for (const QPointer<ExtraCompiler> &compiler : qAsConst(m_extraCompilers)) {
|
||||
if (compiler) {
|
||||
extraCompilers += compiler.data();
|
||||
compilerFiles += Utils::transform<QSet>(compiler->targets(), &Utils::FilePath::toString);
|
||||
}
|
||||
}
|
||||
GeneratedCodeModelSupport::update(extraCompilers);
|
||||
m_extraCompilers.clear();
|
||||
|
||||
auto updateFuture = CppModelManager::instance()
|
||||
->updateProjectInfo(m_generateFutureWatcher.result(), compilerFiles);
|
||||
m_futureSynchronizer.addFuture(updateFuture);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "cpptools_global.h"
|
||||
#include "projectinfo.h"
|
||||
|
||||
#include <projectexplorer/extracompiler.h>
|
||||
#include <utils/futuresynchronizer.h>
|
||||
|
||||
#include <QFutureWatcher>
|
||||
@@ -54,18 +55,26 @@ class CPPTOOLS_EXPORT CppProjectUpdater final : public QObject, public CppProjec
|
||||
|
||||
public:
|
||||
CppProjectUpdater();
|
||||
~CppProjectUpdater() override;
|
||||
|
||||
void update(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo) override;
|
||||
void update(const ProjectExplorer::ProjectUpdateInfo &projectUpdateInfo,
|
||||
const QList<ProjectExplorer::ExtraCompiler *> &extraCompilers);
|
||||
void cancel() override;
|
||||
|
||||
private:
|
||||
void onToolChainRemoved(ProjectExplorer::ToolChain *);
|
||||
void onProjectInfoGenerated();
|
||||
void checkForExtraCompilersFinished();
|
||||
|
||||
private:
|
||||
ProjectExplorer::ProjectUpdateInfo m_projectUpdateInfo;
|
||||
QList<QPointer<ProjectExplorer::ExtraCompiler>> m_extraCompilers;
|
||||
|
||||
QFutureWatcher<ProjectInfo> m_generateFutureWatcher;
|
||||
bool m_isProjectInfoGenerated = false;
|
||||
QSet<QFutureWatcher<void> *> m_extraCompilersFutureWatchers;
|
||||
std::unique_ptr<QFutureInterface<void>> m_projectUpdateFutureInterface;
|
||||
Utils::FutureSynchronizer m_futureSynchronizer;
|
||||
};
|
||||
|
||||
|
||||
@@ -95,14 +95,6 @@ const char LOCATOR_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("CppTools", "C++ Cl
|
||||
const char SYMBOLS_FIND_FILTER_ID[] = "Symbols";
|
||||
const char SYMBOLS_FIND_FILTER_DISPLAY_NAME[] = QT_TRANSLATE_NOOP("CppTools", "C++ Symbols");
|
||||
|
||||
// CLANG-UPGRADE-CHECK: Checks/update URLs.
|
||||
//
|
||||
// Upgrade the version in the URL. Note that we cannot use the macro
|
||||
// CLANG_VERSION here because it might denote a version that was not yet
|
||||
// released (e.g. 6.0.1, but only 6.0.0 was released).
|
||||
constexpr const char TIDY_DOCUMENTATION_URL_TEMPLATE[]
|
||||
= "https://releases.llvm.org/11.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/%1.html";
|
||||
|
||||
constexpr const char CLANG_STATIC_ANALYZER_DOCUMENTATION_URL[]
|
||||
= "https://clang-analyzer.llvm.org/available_checks.html";
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include <cppeditor/cppeditorconstants.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectpanelfactory.h>
|
||||
#include <projectexplorer/projecttree.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
@@ -86,6 +87,7 @@ public:
|
||||
~CppToolsPluginPrivate()
|
||||
{
|
||||
ExtensionSystem::PluginManager::removeObject(&m_cppProjectUpdaterFactory);
|
||||
delete m_clangdSettingsPage;
|
||||
}
|
||||
|
||||
StringTable stringTable;
|
||||
@@ -95,6 +97,7 @@ public:
|
||||
CppFileSettings m_fileSettings;
|
||||
CppFileSettingsPage m_cppFileSettingsPage{&m_fileSettings};
|
||||
CppCodeModelSettingsPage m_cppCodeModelSettingsPage{&m_codeModelSettings};
|
||||
ClangdSettingsPage *m_clangdSettingsPage = nullptr;
|
||||
CppCodeStyleSettingsPage m_cppCodeStyleSettingsPage;
|
||||
CppProjectUpdaterFactory m_cppProjectUpdaterFactory;
|
||||
};
|
||||
@@ -208,6 +211,14 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error)
|
||||
tr("Insert \"#pragma once\" instead of \"#ifndef\" include guards into header file"),
|
||||
[] { return usePragmaOnce() ? QString("true") : QString(); });
|
||||
|
||||
const auto panelFactory = new ProjectExplorer::ProjectPanelFactory;
|
||||
panelFactory->setPriority(100);
|
||||
panelFactory->setDisplayName(tr("Clangd"));
|
||||
panelFactory->setCreateWidgetFunction([](ProjectExplorer::Project *project) {
|
||||
return new ClangdProjectSettingsWidget(project);
|
||||
});
|
||||
ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -218,6 +229,8 @@ void CppToolsPlugin::extensionsInitialized()
|
||||
d->m_fileSettings.fromSettings(ICore::settings());
|
||||
if (!d->m_fileSettings.applySuffixesToMimeDB())
|
||||
qWarning("Unable to apply cpp suffixes to mime database (cpp mime types not found).\n");
|
||||
if (CppModelManager::instance()->isClangCodeModelActive())
|
||||
d->m_clangdSettingsPage = new ClangdSettingsPage;
|
||||
}
|
||||
|
||||
CppCodeModelSettings *CppToolsPlugin::codeModelSettings()
|
||||
|
||||
@@ -312,7 +312,7 @@ QString TemporaryDir::createFile(const QByteArray &relativePath, const QByteArra
|
||||
if (relativePathString.isEmpty() || QFileInfo(relativePathString).isAbsolute())
|
||||
return QString();
|
||||
|
||||
const QString filePath = m_temporaryDir.path() + QLatin1Char('/') + relativePathString;
|
||||
const QString filePath = m_temporaryDir.filePath(relativePathString).path();
|
||||
if (!TestCase::writeFile(filePath, contents))
|
||||
return QString();
|
||||
return filePath;
|
||||
@@ -368,7 +368,7 @@ TemporaryCopiedDir::TemporaryCopiedDir(const QString &sourceDirPath)
|
||||
|
||||
QString TemporaryCopiedDir::absolutePath(const QByteArray &relativePath) const
|
||||
{
|
||||
return m_temporaryDir.path() + QLatin1Char('/') + QString::fromUtf8(relativePath);
|
||||
return m_temporaryDir.filePath(QString::fromUtf8(relativePath)).path();
|
||||
}
|
||||
|
||||
FileWriterAndRemover::FileWriterAndRemover(const QString &filePath, const QByteArray &contents)
|
||||
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
TemporaryDir();
|
||||
|
||||
bool isValid() const { return m_isValid; }
|
||||
QString path() const { return m_temporaryDir.path(); }
|
||||
QString path() const { return m_temporaryDir.path().path(); }
|
||||
|
||||
QString createFile(const QByteArray &relativePath, const QByteArray &contents);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user