Enable macro editing for the Clang indexer

Refactor much of the code from Environment* classes to NameValue* classes
to share it with the preprocessor macro settings.

Change-Id: Ica4ee817aa338230c422b30d91240d266248d226
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2019-05-07 16:51:22 +02:00
parent f636f06b45
commit 4bae5de36b
84 changed files with 2990 additions and 1197 deletions

View File

@@ -4,12 +4,17 @@ add_qtc_plugin(ClangPchManager
DEFINES CLANGPCHMANAGER_LIB
PLUGIN_DEPENDS Core CppTools
SOURCES
clangindexingprojectsettings.cpp clangindexingprojectsettings.h
clangindexingprojectsettingswidget.cpp clangindexingprojectsettingswidget.h clangindexingprojectsettingswidget.ui
clangindexingsettingsmanager.cpp clangindexingsettingsmanager.h
clangpchmanager_global.h
clangpchmanagerplugin.cpp clangpchmanagerplugin.h
pchmanagerclient.cpp pchmanagerclient.h
pchmanagerconnectionclient.cpp pchmanagerconnectionclient.h
pchmanagernotifierinterface.cpp pchmanagernotifierinterface.h
pchmanagerprojectupdater.cpp pchmanagerprojectupdater.h
preprocessormacrocollector.cpp preprocessormacrocollector.h
preprocessormacrowidget.cpp preprocessormacrowidget.h
progressmanager.h
progressmanagerinterface.h
projectupdater.cpp projectupdater.h

View File

@@ -0,0 +1,96 @@
/****************************************************************************
**
** Copyright (C) 2019 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 "clangindexingprojectsettings.h"
#include <projectexplorer/project.h>
namespace ClangPchManager {
namespace {
Utils::NameValueItems fromQVariantMap(const QVariantMap &variantMap,
Utils::NameValueItem::Operation operation)
{
Utils::NameValueItems nameValueItems;
nameValueItems.reserve(variantMap.size());
auto end = variantMap.end();
for (auto iterator = variantMap.cbegin(); iterator != end; ++iterator) // QMap iterators are broken
nameValueItems.push_back({iterator.key(), iterator.value().toString(), operation});
return nameValueItems;
}
} // namespace
ClangIndexingProjectSettings::ClangIndexingProjectSettings(ProjectExplorer::Project *project)
: m_project(project)
{}
void ClangIndexingProjectSettings::saveMacros(const Utils::NameValueItems &items)
{
QVariantMap unsets;
QVariantMap sets;
for (const Utils::NameValueItem &item : items) {
using Operation = Utils::NameValueItem::Operation;
switch (item.operation) {
case Operation::Set:
sets[item.name] = item.value;
break;
case Operation::Unset:
unsets[item.name] = item.value;
break;
default:
break;
}
}
if (sets.size())
m_project->setNamedSettings("set_indexing_macro", sets);
else
m_project->setNamedSettings("set_indexing_macro", {});
if (unsets.size())
m_project->setNamedSettings("unset_indexing_macro", unsets);
else
m_project->setNamedSettings("unset_indexing_macro", {});
}
Utils::NameValueItems ClangIndexingProjectSettings::readMacros() const
{
QVariant unsets = m_project->namedSettings("unset_indexing_macro");
Utils::NameValueItems items = fromQVariantMap(unsets.toMap(), Utils::NameValueItem::Unset);
QVariant sets = m_project->namedSettings("set_indexing_macro");
items += fromQVariantMap(sets.toMap(), Utils::NameValueItem::Set);
return items;
}
} // namespace ClangPchManager

View File

@@ -0,0 +1,50 @@
/****************************************************************************
**
** Copyright (C) 2019 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 "clangpchmanager_global.h"
#include <utils/namevalueitem.h>
namespace ProjectExplorer {
class Project;
}
namespace ClangPchManager {
class CLANGPCHMANAGER_EXPORT ClangIndexingProjectSettings
{
public:
ClangIndexingProjectSettings(ProjectExplorer::Project *project);
Utils::NameValueItems readMacros() const;
void saveMacros(const Utils::NameValueItems &items);
private:
ProjectExplorer::Project *m_project;
};
} // namespace ClangPchManager

View File

@@ -0,0 +1,61 @@
/****************************************************************************
**
** Copyright (C) 2019 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 "clangindexingprojectsettingswidget.h"
#include "ui_clangindexingprojectsettingswidget.h"
#include <cpptools/cppmodelmanager.h>
#include <projectexplorer/project.h>
#include "preprocessormacrocollector.h"
#include "preprocessormacrowidget.h"
namespace ClangPchManager {
ClangIndexingProjectSettingsWidget::ClangIndexingProjectSettingsWidget(ClangIndexingProjectSettings *settings)
: ui(new Ui::ClangIndexingProjectSettingsWidget)
{
ui->setupUi(this);
ui->preprocessorMacrosWidget->setSettings(settings);
}
ClangIndexingProjectSettingsWidget::~ClangIndexingProjectSettingsWidget()
{
delete ui;
}
void ClangIndexingProjectSettingsWidget::onProjectPartsUpdated(ProjectExplorer::Project *project)
{
const CppTools::ProjectInfo projectInfo = CppTools::CppModelManager::instance()->projectInfo(
project);
PreprocessorMacroCollector collector;
for (auto projectPart : projectInfo.projectParts())
collector.add(projectPart->projectMacros);
ui->preprocessorMacrosWidget->setBasePreprocessorMacros(collector.macros());
}
} // namespace ClangPchManager

View File

@@ -0,0 +1,56 @@
/****************************************************************************
**
** Copyright (C) 2019 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 <QWidget>
namespace ProjectExplorer {
class Project;
}
namespace Ui {
class ClangIndexingProjectSettingsWidget;
}
namespace ClangPchManager {
class ClangIndexingProjectSettings;
class ClangIndexingProjectSettingsWidget : public QWidget
{
Q_OBJECT
public:
explicit ClangIndexingProjectSettingsWidget(ClangIndexingProjectSettings *settings);
~ClangIndexingProjectSettingsWidget();
void onProjectPartsUpdated(ProjectExplorer::Project *project);
private:
Ui::ClangIndexingProjectSettingsWidget *ui;
};
} // namespace ClangPchManager

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ClangIndexingProjectSettingsWidget</class>
<widget class="QWidget" name="ClangIndexingProjectSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="ClangPchManager::PreprocessorMacroWidget" name="preprocessorMacrosWidget" native="true"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>ClangPchManager::PreprocessorMacroWidget</class>
<extends>QWidget</extends>
<header>preprocessormacrowidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,55 @@
/****************************************************************************
**
** Copyright (C) 2019 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 "clangindexingsettingsmanager.h"
#include "clangindexingprojectsettings.h"
namespace ClangPchManager {
ClangIndexingSettingsManager::ClangIndexingSettingsManager() = default;
ClangIndexingSettingsManager::~ClangIndexingSettingsManager() = default;
ClangIndexingProjectSettings *ClangIndexingSettingsManager::settings(ProjectExplorer::Project *project)
{
auto &setting = m_settings[project];
if (!setting)
setting = std::make_unique<ClangIndexingProjectSettings>(project);
return setting.get();
}
void ClangIndexingSettingsManager::remove(ProjectExplorer::Project *project)
{
m_settings.erase(project);
}
bool ClangIndexingSettingsManager::hasSettings(ProjectExplorer::Project *project) const
{
return m_settings.find(project) != m_settings.end();
}
} // namespace ClangPchManager

View File

@@ -0,0 +1,56 @@
/****************************************************************************
**
** Copyright (C) 2019 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 "clangpchmanager_global.h"
#include <map>
#include <memory>
namespace ProjectExplorer {
class Project;
}
namespace ClangPchManager {
class ClangIndexingProjectSettings;
class CLANGPCHMANAGER_EXPORT ClangIndexingSettingsManager
{
public:
ClangIndexingSettingsManager();
~ClangIndexingSettingsManager();
ClangIndexingProjectSettings *settings(ProjectExplorer::Project *project);
void remove(ProjectExplorer::Project *project);
bool hasSettings(ProjectExplorer::Project *project) const;
private:
std::map<ProjectExplorer::Project *, std::unique_ptr<ClangIndexingProjectSettings>> m_settings;
};
} // namespace ClangPchManager

View File

@@ -7,18 +7,24 @@ shared|dll {
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/clangindexingprojectsettings.h \
$$PWD/clangindexingsettingsmanager.h \
$$PWD/pchmanagerclient.h \
$$PWD/pchmanagernotifierinterface.h \
$$PWD/pchmanagerconnectionclient.h \
$$PWD/clangpchmanager_global.h \
$$PWD/preprocessormacrocollector.h \
$$PWD/projectupdater.h \
$$PWD/pchmanagerprojectupdater.h \
$$PWD/progressmanager.h \
$$PWD/progressmanagerinterface.h
SOURCES += \
$$PWD/clangindexingprojectsettings.cpp \
$$PWD/clangindexingsettingsmanager.cpp \
$$PWD/pchmanagerclient.cpp \
$$PWD/pchmanagernotifierinterface.cpp \
$$PWD/pchmanagerconnectionclient.cpp \
$$PWD/preprocessormacrocollector.cpp \
$$PWD/projectupdater.cpp \
$$PWD/pchmanagerprojectupdater.cpp

View File

@@ -12,8 +12,15 @@ win32 {
HEADERS += \
$$PWD/clangpchmanagerplugin.h \
clangindexingprojectsettingswidget.h \
preprocessormacrowidget.h \
qtcreatorprojectupdater.h
SOURCES += \
$$PWD/clangpchmanagerplugin.cpp \
clangindexingprojectsettingswidget.cpp \
preprocessormacrowidget.cpp \
qtcreatorprojectupdater.cpp
FORMS += \
clangindexingprojectsettingswidget.ui

View File

@@ -25,8 +25,10 @@
#include "clangpchmanagerplugin.h"
#include "pchmanagerconnectionclient.h"
#include "clangindexingprojectsettingswidget.h"
#include "clangindexingsettingsmanager.h"
#include "pchmanagerclient.h"
#include "pchmanagerconnectionclient.h"
#include "progressmanager.h"
#include "qtcreatorprojectupdater.h"
@@ -38,12 +40,14 @@
#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/projectpanelfactory.h>
#include <utils/hostosinfo.h>
#include <QFutureInterface>
#include <chrono>
#include <map>
using namespace std::chrono_literals;
@@ -58,6 +62,26 @@ QString backendProcessPath()
+ QStringLiteral(QTC_HOST_EXE_SUFFIX);
}
void addIndexingProjectPaneWidget(ClangIndexingSettingsManager &settingsManager)
{
auto factory = new ProjectExplorer::ProjectPanelFactory;
factory->setPriority(120);
factory->setDisplayName(ClangIndexingProjectSettingsWidget::tr("Clang Indexing"));
factory->setCreateWidgetFunction([&](ProjectExplorer::Project *project) {
auto widget = new ClangIndexingProjectSettingsWidget(settingsManager.settings(project));
widget->onProjectPartsUpdated(project);
QObject::connect(CppTools::CppModelManager::instance(),
&CppTools::CppModelManager::projectPartsUpdated,
widget,
&ClangIndexingProjectSettingsWidget::onProjectPartsUpdated);
return widget;
});
ProjectExplorer::ProjectPanelFactory::registerFactory(factory);
}
} // anonymous namespace
class ClangPchManagerPluginData
@@ -83,10 +107,12 @@ public:
ClangBackEnd::ProjectPartsStorage<Sqlite::Database> projectPartsStorage{database};
PchManagerClient pchManagerClient{pchCreationProgressManager, dependencyCreationProgressManager};
PchManagerConnectionClient connectionClient{&pchManagerClient};
ClangIndexingSettingsManager settingsManager;
QtCreatorProjectUpdater<PchManagerProjectUpdater> projectUpdate{connectionClient.serverProxy(),
pchManagerClient,
filePathCache,
projectPartsStorage};
projectPartsStorage,
settingsManager};
};
std::unique_ptr<ClangPchManagerPluginData> ClangPchManagerPlugin::d;
@@ -102,6 +128,8 @@ bool ClangPchManagerPlugin::initialize(const QStringList & /*arguments*/, QStrin
startBackend();
addIndexingProjectPaneWidget(d->settingsManager);
return true;
}
@@ -133,4 +161,9 @@ PchManagerClient &ClangPchManagerPlugin::pchManagerClient()
return d->pchManagerClient;
}
ClangIndexingSettingsManager &ClangPchManagerPlugin::settingsManager()
{
return d->settingsManager;
}
} // namespace ClangRefactoring

View File

@@ -33,6 +33,7 @@
namespace ClangPchManager {
class ClangIndexingSettingsManager;
class ClangPchManagerPluginData;
class PchManagerClient;
@@ -50,6 +51,7 @@ public:
ShutdownFlag aboutToShutdown();
static PchManagerClient &pchManagerClient();
static ClangIndexingSettingsManager &settingsManager();
private:
void startBackend();

View File

@@ -35,8 +35,9 @@ public:
PchManagerProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
PchManagerClient &client,
ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage)
: ProjectUpdater(server, filePathCache, projectPartsStorage)
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
ClangIndexingSettingsManager &settingsManager)
: ProjectUpdater(server, filePathCache, projectPartsStorage, settingsManager)
, m_client(client)
{}

View File

@@ -0,0 +1,68 @@
/****************************************************************************
**
** Copyright (C) 2019 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 "preprocessormacrocollector.h"
namespace ClangPchManager {
namespace {
PreprocessorMacros toSortedMacros(const ProjectExplorer::Macros &macros)
{
PreprocessorMacros sortedMacros;
sortedMacros.reserve(macros.size());
for (const ProjectExplorer::Macro &macro : macros)
if (macro.type == ProjectExplorer::MacroType::Define)
sortedMacros.push_back({QString::fromUtf8(macro.key), QString::fromUtf8(macro.value)});
std::sort(sortedMacros.begin(), sortedMacros.end());
return sortedMacros;
}
} // namespace
void PreprocessorMacroCollector::add(const ProjectExplorer::Macros &macros)
{
PreprocessorMacros sortedMacros = toSortedMacros(macros);
std::sort(sortedMacros.begin(), sortedMacros.end());
PreprocessorMacros mergedMacros;
mergedMacros.reserve(sortedMacros.size() + m_macros.size());
std::set_union(m_macros.begin(),
m_macros.end(),
sortedMacros.begin(),
sortedMacros.end(),
std::back_inserter(mergedMacros));
m_macros = mergedMacros;
}
const PreprocessorMacros &PreprocessorMacroCollector::macros() const
{
return m_macros;
}
} // namespace ClangPchManager

View File

@@ -0,0 +1,51 @@
/****************************************************************************
**
** Copyright (C) 2019 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 <QString>
#include <QVector>
#include <projectexplorer/projectmacro.h>
#include <utility>
namespace ClangPchManager {
using PreprocessorMacro = std::pair<QString, QString>;
using PreprocessorMacros = QVector<PreprocessorMacro>;
class PreprocessorMacroCollector
{
public:
void add(const ProjectExplorer::Macros &macros);
const PreprocessorMacros &macros() const;
private:
PreprocessorMacros m_macros;
};
} // namespace ClangPchManager

View File

@@ -0,0 +1,282 @@
/****************************************************************************
**
** Copyright (C) 2019 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 "preprocessormacrowidget.h"
#include "clangindexingprojectsettings.h"
#include <utils/detailswidget.h>
#include <utils/headerviewstretcher.h>
#include <utils/itemviews.h>
#include <utils/namevaluedictionary.h>
#include <utils/namevalueitem.h>
#include <utils/namevaluemodel.h>
#include <utils/namevaluesdialog.h>
#include <utils/namevaluevalidator.h>
#include <coreplugin/find/itemviewfind.h>
#include <QLineEdit>
#include <QStyledItemDelegate>
#include <QVBoxLayout>
namespace ClangPchManager {
class ProcessorMacroDelegate : public QStyledItemDelegate
{
public:
ProcessorMacroDelegate(Utils::NameValueModel *model, QTreeView *view)
: QStyledItemDelegate(view)
, m_model(model)
, m_view(view)
{}
QWidget *createEditor(QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const override
{
QWidget *w = QStyledItemDelegate::createEditor(parent, option, index);
if (index.column() != 0)
return w;
if (auto edit = qobject_cast<QLineEdit *>(w))
edit->setValidator(new Utils::NameValueValidator(
edit, m_model, m_view, index, PreprocessorMacroWidget::tr("Macro already exists.")));
return w;
}
private:
Utils::NameValueModel *m_model;
QTreeView *m_view;
};
PreprocessorMacroWidget::PreprocessorMacroWidget(QWidget *parent) : QWidget(parent)
{
m_model = std::make_unique<Utils::NameValueModel>();
connect(m_model.get(),
&Utils::NameValueModel::userChangesChanged,
this,
&PreprocessorMacroWidget::userChangesChanged);
connect(m_model.get(),
&QAbstractItemModel::modelReset,
this,
&PreprocessorMacroWidget::invalidateCurrentIndex);
connect(m_model.get(), &Utils::NameValueModel::focusIndex, this, &PreprocessorMacroWidget::focusIndex);
auto vbox = new QVBoxLayout(this);
vbox->setContentsMargins(0, 0, 0, 0);
m_detailsContainer = new Utils::DetailsWidget(this);
auto details = new QWidget(m_detailsContainer);
m_detailsContainer->setWidget(details);
details->setVisible(false);
auto vbox2 = new QVBoxLayout(details);
vbox2->setMargin(0);
auto horizontalLayout = new QHBoxLayout;
horizontalLayout->setMargin(0);
auto tree = new Utils::TreeView(this);
connect(tree, &QAbstractItemView::activated, tree, [tree](const QModelIndex &idx) {
tree->edit(idx);
});
m_preprocessorMacrosView = tree;
m_preprocessorMacrosView->setModel(m_model.get());
m_preprocessorMacrosView->setItemDelegate(
new ProcessorMacroDelegate(m_model.get(), m_preprocessorMacrosView));
m_preprocessorMacrosView->setMinimumHeight(400);
m_preprocessorMacrosView->setRootIsDecorated(false);
m_preprocessorMacrosView->setUniformRowHeights(true);
new Utils::HeaderViewStretcher(m_preprocessorMacrosView->header(), 1);
m_preprocessorMacrosView->setSelectionMode(QAbstractItemView::SingleSelection);
m_preprocessorMacrosView->setSelectionBehavior(QAbstractItemView::SelectItems);
m_preprocessorMacrosView->setFrameShape(QFrame::NoFrame);
QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_preprocessorMacrosView,
Core::ItemViewFind::LightColored);
findWrapper->setFrameStyle(QFrame::StyledPanel);
horizontalLayout->addWidget(findWrapper);
auto buttonLayout = new QVBoxLayout();
m_editButton = new QPushButton(this);
m_editButton->setText(tr("Ed&it"));
buttonLayout->addWidget(m_editButton);
m_addButton = new QPushButton(this);
m_addButton->setText(tr("&Add"));
buttonLayout->addWidget(m_addButton);
m_resetButton = new QPushButton(this);
m_resetButton->setEnabled(false);
m_resetButton->setText(tr("&Reset"));
buttonLayout->addWidget(m_resetButton);
m_unsetButton = new QPushButton(this);
m_unsetButton->setEnabled(false);
m_unsetButton->setText(tr("&Unset"));
buttonLayout->addWidget(m_unsetButton);
buttonLayout->addStretch();
horizontalLayout->addLayout(buttonLayout);
vbox2->addLayout(horizontalLayout);
vbox->addWidget(m_detailsContainer);
connect(m_model.get(),
&QAbstractItemModel::dataChanged,
this,
&PreprocessorMacroWidget::updateButtons);
connect(m_editButton, &QAbstractButton::clicked, this, &PreprocessorMacroWidget::editButtonClicked);
connect(m_addButton, &QAbstractButton::clicked, this, &PreprocessorMacroWidget::addButtonClicked);
connect(m_resetButton, &QAbstractButton::clicked, this, &PreprocessorMacroWidget::removeButtonClicked);
connect(m_unsetButton, &QAbstractButton::clicked, this, &PreprocessorMacroWidget::unsetButtonClicked);
connect(m_preprocessorMacrosView->selectionModel(),
&QItemSelectionModel::currentChanged,
this,
&PreprocessorMacroWidget::currentIndexChanged);
connect(m_detailsContainer,
&Utils::DetailsWidget::linkActivated,
this,
&PreprocessorMacroWidget::linkActivated);
connect(m_model.get(),
&Utils::NameValueModel::userChangesChanged,
this,
&PreprocessorMacroWidget::updateSummaryText);
connect(m_model.get(),
&Utils::NameValueModel::userChangesChanged,
this,
&PreprocessorMacroWidget::saveSettings);
}
void PreprocessorMacroWidget::setBasePreprocessorMacros(const PreprocessorMacros &macros)
{
m_model->setUserChanges(m_settings->readMacros());
m_model->setBaseNameValueDictionary(Utils::NameValueDictionary{macros});
}
void PreprocessorMacroWidget::setSettings(ClangIndexingProjectSettings *settings)
{
m_settings = settings;
}
PreprocessorMacroWidget::~PreprocessorMacroWidget() = default;
void PreprocessorMacroWidget::updateButtons()
{
currentIndexChanged(m_preprocessorMacrosView->currentIndex());
}
void PreprocessorMacroWidget::focusIndex(const QModelIndex &index)
{
m_preprocessorMacrosView->setCurrentIndex(index);
m_preprocessorMacrosView->setFocus();
m_preprocessorMacrosView->scrollTo(index, QAbstractItemView::PositionAtTop);
}
void PreprocessorMacroWidget::invalidateCurrentIndex()
{
currentIndexChanged(QModelIndex());
}
void PreprocessorMacroWidget::editButtonClicked()
{
m_preprocessorMacrosView->edit(m_preprocessorMacrosView->currentIndex());
}
void PreprocessorMacroWidget::addButtonClicked()
{
QModelIndex index = m_model->addVariable();
m_preprocessorMacrosView->setCurrentIndex(index);
m_preprocessorMacrosView->edit(index);
}
void PreprocessorMacroWidget::removeButtonClicked()
{
const QString &name = m_model->indexToVariable(m_preprocessorMacrosView->currentIndex());
m_model->resetVariable(name);
}
void PreprocessorMacroWidget::unsetButtonClicked()
{
const QString &name = m_model->indexToVariable(m_preprocessorMacrosView->currentIndex());
if (!m_model->canReset(name))
m_model->resetVariable(name);
else
m_model->unsetVariable(name);
}
void PreprocessorMacroWidget::currentIndexChanged(const QModelIndex &current)
{
if (current.isValid()) {
m_editButton->setEnabled(true);
const QString &name = m_model->indexToVariable(current);
bool modified = m_model->canReset(name) && m_model->changes(name);
bool unset = m_model->canUnset(name);
m_resetButton->setEnabled(modified || unset);
m_unsetButton->setEnabled(!unset);
} else {
m_editButton->setEnabled(false);
m_resetButton->setEnabled(false);
m_unsetButton->setEnabled(false);
}
}
void PreprocessorMacroWidget::linkActivated(const QString &link)
{
m_detailsContainer->setState(Utils::DetailsWidget::Expanded);
QModelIndex idx = m_model->variableToIndex(link);
focusIndex(idx);
}
void PreprocessorMacroWidget::updateSummaryText()
{
Utils::NameValueItems items = m_model->userChanges();
Utils::NameValueItem::sort(&items);
QString text;
for (const Utils::EnvironmentItem &item : items) {
if (item.name != Utils::NameValueModel::tr("<VARIABLE>")) {
text.append(QLatin1String("<br>"));
if (item.operation == Utils::NameValueItem::Unset)
text.append(tr("Unset <a href=\"%1\"><b>%1</b></a>").arg(item.name.toHtmlEscaped()));
else
text.append(tr("Set <a href=\"%1\"><b>%1</b></a> to <b>%2</b>")
.arg(item.name.toHtmlEscaped(), item.value.toHtmlEscaped()));
}
}
m_detailsContainer->setSummaryText(text);
}
void PreprocessorMacroWidget::saveSettings()
{
m_settings->saveMacros(m_model->userChanges());
}
} // namespace ClangPchManager

View File

@@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2019 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 <QPushButton>
#include <QTreeView>
#include <memory>
namespace Utils {
class DetailsWidget;
class NameValueModel;
} // namespace Utils
namespace ClangPchManager {
class ClangIndexingProjectSettings;
using PreprocessorMacro = std::pair<QString, QString>;
using PreprocessorMacros = QVector<PreprocessorMacro>;
class PreprocessorMacroWidget : public QWidget
{
Q_OBJECT
public:
explicit PreprocessorMacroWidget(QWidget *parent = nullptr);
~PreprocessorMacroWidget() override;
void setBasePreprocessorMacros(const PreprocessorMacros &macros);
void setSettings(ClangIndexingProjectSettings *settings);
signals:
void userChangesChanged();
private:
void updateButtons();
void focusIndex(const QModelIndex &index);
void invalidateCurrentIndex();
void editButtonClicked();
void addButtonClicked();
void removeButtonClicked();
void unsetButtonClicked();
void currentIndexChanged(const QModelIndex &current);
void linkActivated(const QString &link);
void updateSummaryText();
void saveSettings();
private:
std::unique_ptr<Utils::NameValueModel> m_model;
Utils::DetailsWidget *m_detailsContainer;
QTreeView *m_preprocessorMacrosView;
QPushButton *m_editButton;
QPushButton *m_addButton;
QPushButton *m_resetButton;
QPushButton *m_unsetButton;
ClangIndexingProjectSettings *m_settings = {};
};
} // namespace ClangPchManager

View File

@@ -27,6 +27,8 @@
#include "pchmanagerclient.h"
#include <clangindexingprojectsettings.h>
#include <clangindexingsettingsmanager.h>
#include <filepathid.h>
#include <pchmanagerserverinterface.h>
#include <removegeneratedfilesmessage.h>
@@ -42,6 +44,7 @@
#include <projectexplorer/buildconfiguration.h>
#include <utils/algorithm.h>
#include <utils/namevalueitem.h>
#include <algorithm>
#include <functional>
@@ -175,9 +178,63 @@ void cleanupMacros(ClangBackEnd::CompilerMacros &macros)
macros.erase(newEnd, macros.end());
}
void updateWithSettings(ClangBackEnd::CompilerMacros &macros,
Utils::NameValueItems &&settingsItems,
int &index)
{
std::sort(settingsItems.begin(), settingsItems.end(), [](const auto &first, const auto &second) {
return std::tie(first.operation, first.name, first.value)
< std::tie(first.operation, second.name, second.value);
});
auto point = std::partition_point(settingsItems.begin(), settingsItems.end(), [](const auto &entry) {
return entry.operation == Utils::NameValueItem::Set;
});
std::transform(
settingsItems.begin(),
point,
std::back_inserter(macros),
[&](const Utils::NameValueItem &settingsMacro) {
return ClangBackEnd::CompilerMacro{settingsMacro.name, settingsMacro.value, ++index};
});
std::sort(macros.begin(), macros.end(), [](const auto &first, const auto &second) {
return std::tie(first.key, first.value) < std::tie(second.key, second.value);
});
ClangBackEnd::CompilerMacros result;
result.reserve(macros.size());
ClangBackEnd::CompilerMacros convertedSettingsMacros;
convertedSettingsMacros.resize(std::distance(point, settingsItems.end()));
std::transform(
point,
settingsItems.end(),
std::back_inserter(convertedSettingsMacros),
[&](const Utils::NameValueItem &settingsMacro) {
return ClangBackEnd::CompilerMacro{settingsMacro.name, settingsMacro.value, ++index};
});
std::set_difference(macros.begin(),
macros.end(),
convertedSettingsMacros.begin(),
convertedSettingsMacros.end(),
std::back_inserter(result),
[](const ClangBackEnd::CompilerMacro &first,
const ClangBackEnd::CompilerMacro &second) {
return std::tie(first.key, first.value)
< std::tie(second.key, second.value);
});
macros = std::move(result);
}
} // namespace
ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(const ProjectExplorer::Macros &projectMacros)
ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(
const ProjectExplorer::Macros &projectMacros, Utils::NameValueItems &&settingsMacros) const
{
int index = 0;
auto macros = Utils::transform<ClangBackEnd::CompilerMacros>(
@@ -186,6 +243,7 @@ ClangBackEnd::CompilerMacros ProjectUpdater::createCompilerMacros(const ProjectE
});
cleanupMacros(macros);
updateWithSettings(macros, std::move(settingsMacros), index);
std::sort(macros.begin(), macros.end());
@@ -291,9 +349,12 @@ ClangBackEnd::ProjectPartContainer ProjectUpdater::toProjectPartContainer(
ClangBackEnd::ProjectPartId projectPartId = m_projectPartsStorage.fetchProjectPartId(
projectPartName);
ClangIndexingProjectSettings *settings = m_settingsManager.settings(projectPart->project);
return ClangBackEnd::ProjectPartContainer(projectPartId,
Utils::SmallStringVector(arguments),
createCompilerMacros(projectPart->projectMacros),
createCompilerMacros(projectPart->projectMacros,
settings->readMacros()),
std::move(includeSearchPaths.system),
std::move(includeSearchPaths.project),
std::move(headerAndSources.headers),

View File

@@ -37,6 +37,8 @@
#include <projectexplorer/headerpath.h>
#include <utils/environmentfwd.h>
namespace ProjectExplorer {
class Macro;
using Macros = QVector<Macro>;
@@ -59,6 +61,8 @@ namespace ClangPchManager {
class HeaderAndSources;
class PchManagerClient;
class ClangIndexingSettingsManager;
class ClangIndexingProjectSettings;
class CLANGPCHMANAGER_EXPORT ProjectUpdater
{
@@ -71,10 +75,12 @@ public:
ProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage)
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
ClangIndexingSettingsManager &settingsManager)
: m_server(server)
, m_filePathCache(filePathCache)
, m_projectPartsStorage(projectPartsStorage)
, m_settingsManager(settingsManager)
{}
void updateProjectParts(const std::vector<CppTools::ProjectPart *> &projectParts,
@@ -98,8 +104,8 @@ public:
void addToHeaderAndSources(HeaderAndSources &headerAndSources,
const CppTools::ProjectFile &projectFile) const;
static QStringList toolChainArguments(CppTools::ProjectPart *projectPart);
static ClangBackEnd::CompilerMacros createCompilerMacros(
const ProjectExplorer::Macros &projectMacros);
ClangBackEnd::CompilerMacros createCompilerMacros(const ProjectExplorer::Macros &projectMacros,
Utils::NameValueItems &&settingsMacros) const;
static SystemAndProjectIncludeSearchPaths createIncludeSearchPaths(
const CppTools::ProjectPart &projectPart);
static ClangBackEnd::FilePaths createExcludedPaths(
@@ -115,6 +121,7 @@ private:
ClangBackEnd::ProjectManagementServerInterface &m_server;
ClangBackEnd::FilePathCachingInterface &m_filePathCache;
ClangBackEnd::ProjectPartsStorageInterface &m_projectPartsStorage;
ClangIndexingSettingsManager &m_settingsManager;
};
} // namespace ClangPchManager

View File

@@ -59,8 +59,9 @@ public:
QtCreatorProjectUpdater(ClangBackEnd::ProjectManagementServerInterface &server,
ClientType &client,
ClangBackEnd::FilePathCachingInterface &filePathCache,
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage)
: ProjectUpdaterType(server, client, filePathCache, projectPartsStorage)
ClangBackEnd::ProjectPartsStorageInterface &projectPartsStorage,
ClangIndexingSettingsManager &settingsManager)
: ProjectUpdaterType(server, client, filePathCache, projectPartsStorage, settingsManager)
{
connectToCppModelManager();
}
@@ -74,7 +75,6 @@ public:
void projectPartsUpdated(ProjectExplorer::Project *project)
{
ProjectUpdaterType::updateProjectParts(Internal::createProjectParts(project), {}); // TODO add support for toolchainarguments
}