diff --git a/src/plugins/clangcodemodel/CMakeLists.txt b/src/plugins/clangcodemodel/CMakeLists.txt index 7f60420b5a0..50007413e15 100644 --- a/src/plugins/clangcodemodel/CMakeLists.txt +++ b/src/plugins/clangcodemodel/CMakeLists.txt @@ -21,6 +21,7 @@ add_qtc_plugin(ClangCodeModel clangdfindreferences.cpp clangdfindreferences.h clangdfollowsymbol.cpp clangdfollowsymbol.h clangdiagnostictooltipwidget.cpp clangdiagnostictooltipwidget.h + clangdmemoryusagewidget.cpp clangdmemoryusagewidget.h clangdquickfixes.cpp clangdquickfixes.h clangdqpropertyhighlighter.cpp clangdqpropertyhighlighter.h clangdsemantichighlighting.cpp clangdsemantichighlighting.h diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index 11a356d46d9..6ba0e589009 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -44,6 +44,8 @@ QtcPlugin { "clangdiagnostictooltipwidget.h", "clangdlocatorfilters.cpp", "clangdlocatorfilters.h", + "clangdmemoryusagewidget.cpp", + "clangdmemoryusagewidget.h", "clangdqpropertyhighlighter.cpp", "clangdqpropertyhighlighter.h", "clangdquickfixes.cpp", diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 2994be350f7..2e308d66a54 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -31,6 +31,7 @@ #include "clangdfindreferences.h" #include "clangdfollowsymbol.h" #include "clangdlocatorfilters.h" +#include "clangdmemoryusagewidget.h" #include "clangdquickfixes.h" #include "clangdswitchdecldef.h" #include "clangtextmark.h" @@ -71,20 +72,15 @@ #include #include #include -#include #include #include #include #include #include -#include -#include #include #include #include -#include -#include #include #include @@ -255,24 +251,6 @@ private: std::unordered_map> m_data; }; -class MemoryTreeModel; -class MemoryUsageWidget : public QWidget -{ - Q_DECLARE_TR_FUNCTIONS(MemoryUsageWidget) -public: - MemoryUsageWidget(ClangdClient *client); - ~MemoryUsageWidget(); - -private: - void setupUi(); - void getMemoryTree(); - - ClangdClient * const m_client; - MemoryTreeModel * const m_model; - Utils::TreeView m_view; - Utils::optional m_currentRequest; -}; - class HighlightingData { public: @@ -564,7 +542,7 @@ QTextCursor ClangdClient::adjustedCursorForHighlighting(const QTextCursor &curso const LanguageClient::Client::CustomInspectorTabs ClangdClient::createCustomInspectorTabs() { - return {std::make_pair(new MemoryUsageWidget(this), tr("Memory Usage"))}; + return {std::make_pair(new ClangdMemoryUsageWidget(this), tr("Memory Usage"))}; } class ClangdDiagnosticManager : public LanguageClient::DiagnosticManager @@ -1405,139 +1383,5 @@ MessageId ClangdClient::Private::getAndHandleAst(const TextDocOrFile &doc, return requestAst(q, filePath, range, wrapperHandler); } -class MemoryTree : public JsonObject -{ -public: - using JsonObject::JsonObject; - - // number of bytes used, including child components - qint64 total() const { return qint64(typedValue(totalKey())); } - - // number of bytes used, excluding child components - qint64 self() const { return qint64(typedValue(selfKey())); } - - // named child components - using NamedComponent = std::pair; - QList children() const - { - QList components; - const auto obj = operator const QJsonObject &(); - for (auto it = obj.begin(); it != obj.end(); ++it) { - if (it.key() == totalKey() || it.key() == selfKey()) - continue; - components << std::make_pair(MemoryTree(it.value()), it.key()); - } - return components; - } - -private: - static QString totalKey() { return QLatin1String("_total"); } - static QString selfKey() { return QLatin1String("_self"); } -}; - -class MemoryTreeItem : public Utils::TreeItem -{ - Q_DECLARE_TR_FUNCTIONS(MemoryTreeItem) -public: - MemoryTreeItem(const QString &displayName, const MemoryTree &tree) - : m_displayName(displayName), m_bytesUsed(tree.total()) - { - for (const MemoryTree::NamedComponent &component : tree.children()) - appendChild(new MemoryTreeItem(component.second, component.first)); - } - -private: - QVariant data(int column, int role) const override - { - switch (role) { - case Qt::DisplayRole: - if (column == 0) - return m_displayName; - return memString(); - case Qt::TextAlignmentRole: - if (column == 1) - return Qt::AlignRight; - break; - default: - break; - } - return {}; - } - - QString memString() const - { - static const QList> factors{ - std::make_pair(1000000000, QString("GB")), - std::make_pair(1000000, QString("MB")), - std::make_pair(1000, QString("KB")), - }; - for (const auto &factor : factors) { - if (m_bytesUsed > factor.first) - return QString::number(qint64(std::round(double(m_bytesUsed) / factor.first))) - + ' ' + factor.second; - } - return QString::number(m_bytesUsed) + " B"; - } - - const QString m_displayName; - const qint64 m_bytesUsed; -}; - -class MemoryTreeModel : public Utils::BaseTreeModel -{ -public: - MemoryTreeModel(QObject *parent) : BaseTreeModel(parent) - { - setHeader({MemoryUsageWidget::tr("Component"), MemoryUsageWidget::tr("Total Memory")}); - } - - void update(const MemoryTree &tree) - { - setRootItem(new MemoryTreeItem({}, tree)); - } -}; - -MemoryUsageWidget::MemoryUsageWidget(ClangdClient *client) - : m_client(client), m_model(new MemoryTreeModel(this)) -{ - setupUi(); - getMemoryTree(); -} - -MemoryUsageWidget::~MemoryUsageWidget() -{ - if (m_currentRequest.has_value()) - m_client->cancelRequest(m_currentRequest.value()); -} - -void MemoryUsageWidget::setupUi() -{ - const auto layout = new QVBoxLayout(this); - m_view.setContextMenuPolicy(Qt::CustomContextMenu); - m_view.header()->setSectionResizeMode(QHeaderView::ResizeToContents); - m_view.header()->setStretchLastSection(false); - m_view.setModel(m_model); - layout->addWidget(&m_view); - connect(&m_view, &QWidget::customContextMenuRequested, this, [this](const QPoint &pos) { - QMenu menu; - menu.addAction(tr("Update"), [this] { getMemoryTree(); }); - menu.exec(m_view.mapToGlobal(pos)); - }); -} - -void MemoryUsageWidget::getMemoryTree() -{ - Request request("$/memoryUsage", {}); - request.setResponseCallback([this](decltype(request)::Response response) { - m_currentRequest.reset(); - qCDebug(clangdLog) << "received memory usage response"; - if (const auto result = response.result()) - m_model->update(*result); - }); - qCDebug(clangdLog) << "sending memory usage request"; - m_currentRequest = request.id(); - m_client->sendMessage(request, ClangdClient::SendDocUpdates::Ignore); -} - } // namespace Internal } // namespace ClangCodeModel diff --git a/src/plugins/clangcodemodel/clangdmemoryusagewidget.cpp b/src/plugins/clangcodemodel/clangdmemoryusagewidget.cpp new file mode 100644 index 00000000000..6c64a4abe28 --- /dev/null +++ b/src/plugins/clangcodemodel/clangdmemoryusagewidget.cpp @@ -0,0 +1,200 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 "clangdmemoryusagewidget.h" + +#include "clangdclient.h" + +#include +#include +#include + +#include +#include +#include +#include + +using namespace LanguageServerProtocol; +using namespace Utils; + +namespace ClangCodeModel::Internal { + +class MemoryTree : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // number of bytes used, including child components + qint64 total() const { return qint64(typedValue(totalKey())); } + + // number of bytes used, excluding child components + qint64 self() const { return qint64(typedValue(selfKey())); } + + // named child components + using NamedComponent = std::pair; + QList children() const + { + QList components; + const auto obj = operator const QJsonObject &(); + for (auto it = obj.begin(); it != obj.end(); ++it) { + if (it.key() == totalKey() || it.key() == selfKey()) + continue; + components << std::make_pair(MemoryTree(it.value()), it.key()); + } + return components; + } + +private: + static QString totalKey() { return QLatin1String("_total"); } + static QString selfKey() { return QLatin1String("_self"); } +}; + + +class MemoryTreeItem : public TreeItem +{ + Q_DECLARE_TR_FUNCTIONS(ClangCodeModel) +public: + MemoryTreeItem(const QString &displayName, const MemoryTree &tree) + : m_displayName(displayName), m_bytesUsed(tree.total()) + { + for (const MemoryTree::NamedComponent &component : tree.children()) + appendChild(new MemoryTreeItem(component.second, component.first)); + } + +private: + QVariant data(int column, int role) const override + { + switch (role) { + case Qt::DisplayRole: + if (column == 0) + return m_displayName; + return memString(); + case Qt::TextAlignmentRole: + if (column == 1) + return Qt::AlignRight; + break; + default: + break; + } + return {}; + } + + QString memString() const + { + static const QList> factors{ + std::make_pair(1000000000, QString("GB")), + std::make_pair(1000000, QString("MB")), + std::make_pair(1000, QString("KB")), + }; + for (const auto &factor : factors) { + if (m_bytesUsed > factor.first) + return QString::number(qint64(std::round(double(m_bytesUsed) / factor.first))) + + ' ' + factor.second; + } + return QString::number(m_bytesUsed) + " B"; + } + + const QString m_displayName; + const qint64 m_bytesUsed; +}; + + +class MemoryTreeModel : public BaseTreeModel +{ +public: + MemoryTreeModel() + { + setHeader({ClangdMemoryUsageWidget::tr("Component"), + ClangdMemoryUsageWidget::tr("Total Memory")}); + } + + void update(const MemoryTree &tree) + { + setRootItem(new MemoryTreeItem({}, tree)); + } +}; + + +class ClangdMemoryUsageWidget::Private +{ +public: + Private(ClangdMemoryUsageWidget *q, ClangdClient *client) : q(q), client(client) + { + setupUi(); + getMemoryTree(); + } + + void setupUi(); + void getMemoryTree(); + + ClangdMemoryUsageWidget * const q; + const QPointer client; + MemoryTreeModel model; + TreeView view; + Utils::optional currentRequest; +}; + +ClangdMemoryUsageWidget::ClangdMemoryUsageWidget(ClangdClient *client) + : d(new Private(this, client)) +{ +} + +ClangdMemoryUsageWidget::~ClangdMemoryUsageWidget() +{ + if (d->client && d->currentRequest.has_value()) + d->client->cancelRequest(d->currentRequest.value()); + delete d; +} + +void ClangdMemoryUsageWidget::Private::setupUi() +{ + const auto layout = new QVBoxLayout(q); + view.setContextMenuPolicy(Qt::CustomContextMenu); + view.header()->setSectionResizeMode(QHeaderView::ResizeToContents); + view.header()->setStretchLastSection(false); + view.setModel(&model); + layout->addWidget(&view); + QObject::connect(&view, &QWidget::customContextMenuRequested, q, [this](const QPoint &pos) { + QMenu menu; + menu.addAction(tr("Update"), [this] { getMemoryTree(); }); + menu.exec(view.mapToGlobal(pos)); + }); +} + +void ClangdMemoryUsageWidget::Private::getMemoryTree() +{ + Request request("$/memoryUsage", {}); + request.setResponseCallback([this](decltype(request)::Response response) { + currentRequest.reset(); + qCDebug(clangdLog) << "received memory usage response"; + if (const auto result = response.result()) + model.update(*result); + }); + qCDebug(clangdLog) << "sending memory usage request"; + currentRequest = request.id(); + client->sendMessage(request, ClangdClient::SendDocUpdates::Ignore); +} + +} // namespace ClangCodeModel::Internal diff --git a/src/plugins/clangcodemodel/clangdmemoryusagewidget.h b/src/plugins/clangcodemodel/clangdmemoryusagewidget.h new file mode 100644 index 00000000000..8c1a9b8f97f --- /dev/null +++ b/src/plugins/clangcodemodel/clangdmemoryusagewidget.h @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 +#include + +namespace ClangCodeModel::Internal { +class ClangdClient; + +class ClangdMemoryUsageWidget : public QWidget +{ + Q_DECLARE_TR_FUNCTIONS(ClangCodeModel) +public: + explicit ClangdMemoryUsageWidget(ClangdClient *client); + ~ClangdMemoryUsageWidget(); + + class Private; + Private * const d; +}; + +} // namespace ClangCodeModel::Internal +