forked from qt-creator/qt-creator
ClangCodeModel: Provide outline via clangd
Note that we used to encode the information about symbol visibility and static-ness in the icons, which we can't do anymore, because clangd does not provide this information. On the upside, this change likely fixes a ton of bugs, as our own outline was rather "quirky". Change-Id: I099f11ec4e3c6f52cd461fb43080bbdde3bed5e5 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -40,6 +40,8 @@
|
||||
#include <QUrl>
|
||||
#include <QList>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace LanguageServerProtocol {
|
||||
|
||||
class LANGUAGESERVERPROTOCOL_EXPORT DocumentUri : public QUrl
|
||||
@@ -560,6 +562,7 @@ enum class SymbolKind {
|
||||
TypeParameter = 26,
|
||||
LastSymbolKind = TypeParameter,
|
||||
};
|
||||
using SymbolStringifier = std::function<QString(SymbolKind, const QString &, const QString &)>;
|
||||
|
||||
namespace CompletionItemKind {
|
||||
enum Kind {
|
||||
|
@@ -732,6 +732,31 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
|
||||
const auto hideDiagsHandler = []{ ClangDiagnosticManager::clearTaskHubIssues(); };
|
||||
setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler);
|
||||
|
||||
static const auto symbolStringifier = [](SymbolKind kind, const QString &name,
|
||||
const QString &detail) -> QString
|
||||
{
|
||||
switch (kind) {
|
||||
case LanguageServerProtocol::SymbolKind::Constructor:
|
||||
return name + detail;
|
||||
case LanguageServerProtocol::SymbolKind::Method:
|
||||
case LanguageServerProtocol::SymbolKind::Function: {
|
||||
const int parenOffset = detail.indexOf(" (");
|
||||
if (parenOffset == -1)
|
||||
return name;
|
||||
return name + detail.mid(parenOffset + 1) + " -> " + detail.mid(0, parenOffset);
|
||||
}
|
||||
case LanguageServerProtocol::SymbolKind::Variable:
|
||||
case LanguageServerProtocol::SymbolKind::Field:
|
||||
case LanguageServerProtocol::SymbolKind::Constant:
|
||||
if (detail.isEmpty())
|
||||
return name;
|
||||
return name + " -> " + detail;
|
||||
default:
|
||||
return name;
|
||||
}
|
||||
};
|
||||
setSymbolStringifier(symbolStringifier);
|
||||
|
||||
hoverHandler()->setHelpItemProvider([this](const HoverRequest::Response &response,
|
||||
const DocumentUri &uri) {
|
||||
gatherHelpItemForTooltip(response, uri);
|
||||
|
@@ -171,6 +171,11 @@ std::unique_ptr<CppTools::AbstractOverviewModel> ClangModelManagerSupport::creat
|
||||
return std::make_unique<OverviewModel>();
|
||||
}
|
||||
|
||||
bool ClangModelManagerSupport::supportsOutline(const TextEditor::TextDocument *document) const
|
||||
{
|
||||
return !clientForFile(document->filePath());
|
||||
}
|
||||
|
||||
CppTools::BaseEditorDocumentProcessor *ClangModelManagerSupport::createEditorDocumentProcessor(
|
||||
TextEditor::TextDocument *baseTextDocument)
|
||||
{
|
||||
@@ -344,7 +349,7 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr
|
||||
}
|
||||
|
||||
ClangdClient *ClangModelManagerSupport::clientForProject(
|
||||
const ProjectExplorer::Project *project)
|
||||
const ProjectExplorer::Project *project) const
|
||||
{
|
||||
const QList<Client *> clients = Utils::filtered(
|
||||
LanguageClientManager::clientsForProject(project),
|
||||
@@ -357,7 +362,7 @@ ClangdClient *ClangModelManagerSupport::clientForProject(
|
||||
return clients.empty() ? nullptr : qobject_cast<ClangdClient *>(clients.first());
|
||||
}
|
||||
|
||||
ClangdClient *ClangModelManagerSupport::clientForFile(const Utils::FilePath &file)
|
||||
ClangdClient *ClangModelManagerSupport::clientForFile(const Utils::FilePath &file) const
|
||||
{
|
||||
return clientForProject(ProjectExplorer::SessionManager::projectForFile(file));
|
||||
}
|
||||
|
@@ -72,6 +72,7 @@ public:
|
||||
CppTools::FollowSymbolInterface &followSymbolInterface() override;
|
||||
CppTools::RefactoringEngineInterface &refactoringEngineInterface() override;
|
||||
std::unique_ptr<CppTools::AbstractOverviewModel> createOverviewModel() override;
|
||||
bool supportsOutline(const TextEditor::TextDocument *document) const override;
|
||||
|
||||
BackendCommunicator &communicator();
|
||||
QString dummyUiHeaderOnDiskDirPath() const;
|
||||
@@ -79,8 +80,8 @@ public:
|
||||
|
||||
ClangProjectSettings &projectSettings(ProjectExplorer::Project *project) const;
|
||||
|
||||
ClangdClient *clientForProject(const ProjectExplorer::Project *project);
|
||||
ClangdClient *clientForFile(const Utils::FilePath &file);
|
||||
ClangdClient *clientForProject(const ProjectExplorer::Project *project) const;
|
||||
ClangdClient *clientForFile(const Utils::FilePath &file) const;
|
||||
|
||||
static ClangModelManagerSupport *instance();
|
||||
|
||||
|
@@ -118,7 +118,7 @@ public:
|
||||
QPointer<CppModelManager> m_modelManager;
|
||||
|
||||
CppEditorDocument *m_cppEditorDocument;
|
||||
CppEditorOutline *m_cppEditorOutline;
|
||||
CppEditorOutline *m_cppEditorOutline = nullptr;
|
||||
|
||||
QTimer m_updateFunctionDeclDefLinkTimer;
|
||||
SemanticInfo m_lastSemanticInfo;
|
||||
@@ -139,7 +139,6 @@ public:
|
||||
CppEditorWidgetPrivate::CppEditorWidgetPrivate(CppEditorWidget *q)
|
||||
: m_modelManager(CppModelManager::instance())
|
||||
, m_cppEditorDocument(qobject_cast<CppEditorDocument *>(q->textDocument()))
|
||||
, m_cppEditorOutline(new CppEditorOutline(q))
|
||||
, m_declDefLinkFinder(new FunctionDeclDefLinkFinder(q))
|
||||
, m_localRenaming(q)
|
||||
, m_useSelectionsUpdater(q)
|
||||
@@ -160,8 +159,11 @@ void CppEditorWidget::finalizeInitialization()
|
||||
|
||||
// clang-format off
|
||||
// function combo box sorting
|
||||
connect(CppEditorPlugin::instance(), &CppEditorPlugin::outlineSortingChanged,
|
||||
outline(), &CppEditorOutline::setSorted);
|
||||
if (CppModelManager::supportsOutline(d->m_cppEditorDocument)) {
|
||||
d->m_cppEditorOutline = new CppEditorOutline(this);
|
||||
connect(CppEditorPlugin::instance(), &CppEditorPlugin::outlineSortingChanged,
|
||||
outline(), &CppEditorOutline::setSorted);
|
||||
}
|
||||
|
||||
connect(d->m_cppEditorDocument, &CppEditorDocument::codeWarningsUpdated,
|
||||
this, &CppEditorWidget::onCodeWarningsUpdated);
|
||||
@@ -195,8 +197,10 @@ void CppEditorWidget::finalizeInitialization()
|
||||
});
|
||||
connect(&d->m_localRenaming, &CppLocalRenaming::processKeyPressNormally,
|
||||
this, &CppEditorWidget::processKeyNormally);
|
||||
connect(this, &QPlainTextEdit::cursorPositionChanged,
|
||||
d->m_cppEditorOutline, &CppEditorOutline::updateIndex);
|
||||
if (d->m_cppEditorOutline) {
|
||||
connect(this, &QPlainTextEdit::cursorPositionChanged,
|
||||
d->m_cppEditorOutline, &CppEditorOutline::updateIndex);
|
||||
}
|
||||
|
||||
connect(cppEditorDocument(), &CppEditorDocument::preprocessorSettingsChanged, this,
|
||||
[this](bool customSettings) {
|
||||
@@ -232,7 +236,8 @@ void CppEditorWidget::finalizeInitialization()
|
||||
});
|
||||
|
||||
// Toolbar: Outline/Overview combo box
|
||||
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_cppEditorOutline->widget());
|
||||
if (d->m_cppEditorOutline)
|
||||
insertExtraToolBarWidget(TextEditorWidget::Left, d->m_cppEditorOutline->widget());
|
||||
|
||||
// clang-format on
|
||||
// Toolbar: '#' Button
|
||||
@@ -266,7 +271,8 @@ void CppEditorWidget::finalizeInitializationAfterDuplication(TextEditorWidget *o
|
||||
|
||||
if (cppEditorWidget->isSemanticInfoValidExceptLocalUses())
|
||||
updateSemanticInfo(cppEditorWidget->semanticInfo());
|
||||
d->m_cppEditorOutline->update();
|
||||
if (d->m_cppEditorOutline)
|
||||
d->m_cppEditorOutline->update();
|
||||
const Id selectionKind = CodeWarningsSelection;
|
||||
setExtraSelections(selectionKind, cppEditorWidget->extraSelections(selectionKind));
|
||||
|
||||
@@ -325,7 +331,8 @@ void CppEditorWidget::selectAll()
|
||||
|
||||
void CppEditorWidget::onCppDocumentUpdated()
|
||||
{
|
||||
d->m_cppEditorOutline->update();
|
||||
if (d->m_cppEditorOutline)
|
||||
d->m_cppEditorOutline->update();
|
||||
}
|
||||
|
||||
void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
|
||||
|
@@ -28,6 +28,7 @@
|
||||
#include "cppeditor.h"
|
||||
#include <cpptools/cppeditoroutline.h>
|
||||
|
||||
#include <cpptools/cppmodelmanager.h>
|
||||
#include <cpptools/cppoverviewmodel.h>
|
||||
|
||||
#include <texteditor/textdocument.h>
|
||||
@@ -212,7 +213,10 @@ bool CppOutlineWidget::syncCursor()
|
||||
|
||||
bool CppOutlineWidgetFactory::supportsEditor(Core::IEditor *editor) const
|
||||
{
|
||||
return qobject_cast<CppEditor*>(editor);
|
||||
const auto cppEditor = qobject_cast<CppEditor*>(editor);
|
||||
if (!cppEditor)
|
||||
return false;
|
||||
return CppTools::CppModelManager::supportsOutline(cppEditor->textDocument());
|
||||
}
|
||||
|
||||
TextEditor::IOutlineWidget *CppOutlineWidgetFactory::createWidget(Core::IEditor *editor)
|
||||
|
@@ -1310,6 +1310,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;
|
||||
|
@@ -142,6 +142,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
|
||||
|
@@ -1003,6 +1003,16 @@ void Client::setDiagnosticsHandlers(const TextMarkCreator &textMarkCreator,
|
||||
m_diagnosticManager.setDiagnosticsHandlers(textMarkCreator, hideHandler);
|
||||
}
|
||||
|
||||
void Client::setSymbolStringifier(const LanguageServerProtocol::SymbolStringifier &stringifier)
|
||||
{
|
||||
m_symbolStringifier = stringifier;
|
||||
}
|
||||
|
||||
SymbolStringifier Client::symbolStringifier() const
|
||||
{
|
||||
return m_symbolStringifier;
|
||||
}
|
||||
|
||||
void Client::start()
|
||||
{
|
||||
if (m_clientInterface->start())
|
||||
|
@@ -174,6 +174,8 @@ public:
|
||||
const LanguageServerProtocol::Diagnostic &diag) const;
|
||||
void setDiagnosticsHandlers(const TextMarkCreator &textMarkCreator,
|
||||
const HideDiagnosticsHandler &hideHandler);
|
||||
void setSymbolStringifier(const LanguageServerProtocol::SymbolStringifier &stringifier);
|
||||
LanguageServerProtocol::SymbolStringifier symbolStringifier() const;
|
||||
|
||||
// logging
|
||||
void log(const QString &message) const;
|
||||
@@ -270,6 +272,7 @@ private:
|
||||
SemanticTokenSupport m_tokentSupport;
|
||||
QString m_serverName;
|
||||
QString m_serverVersion;
|
||||
LanguageServerProtocol::SymbolStringifier m_symbolStringifier;
|
||||
bool m_locatorsEnabled = true;
|
||||
};
|
||||
|
||||
|
@@ -55,14 +55,15 @@ public:
|
||||
, m_type(info.kind())
|
||||
{ }
|
||||
|
||||
LanguageClientOutlineItem(const DocumentSymbol &info)
|
||||
LanguageClientOutlineItem(const DocumentSymbol &info, const SymbolStringifier &stringifier)
|
||||
: m_name(info.name())
|
||||
, m_detail(info.detail().value_or(QString()))
|
||||
, m_range(info.range())
|
||||
, m_symbolStringifier(stringifier)
|
||||
, m_type(info.kind())
|
||||
{
|
||||
for (const DocumentSymbol &child : info.children().value_or(QList<DocumentSymbol>()))
|
||||
appendChild(new LanguageClientOutlineItem(child));
|
||||
appendChild(new LanguageClientOutlineItem(child, stringifier));
|
||||
}
|
||||
|
||||
// TreeItem interface
|
||||
@@ -72,7 +73,9 @@ public:
|
||||
case Qt::DecorationRole:
|
||||
return symbolIcon(m_type);
|
||||
case Qt::DisplayRole:
|
||||
return m_name;
|
||||
return m_symbolStringifier
|
||||
? m_symbolStringifier(static_cast<SymbolKind>(m_type), m_name, m_detail)
|
||||
: m_name;
|
||||
default:
|
||||
return Utils::TreeItem::data(column, role);
|
||||
}
|
||||
@@ -85,6 +88,7 @@ private:
|
||||
QString m_name;
|
||||
QString m_detail;
|
||||
Range m_range;
|
||||
SymbolStringifier m_symbolStringifier;
|
||||
int m_type = -1;
|
||||
};
|
||||
|
||||
@@ -102,8 +106,16 @@ public:
|
||||
{
|
||||
clear();
|
||||
for (const DocumentSymbol &symbol : info)
|
||||
rootItem()->appendChild(new LanguageClientOutlineItem(symbol));
|
||||
rootItem()->appendChild(new LanguageClientOutlineItem(symbol, m_symbolStringifier));
|
||||
}
|
||||
|
||||
void setSymbolStringifier(const SymbolStringifier &stringifier)
|
||||
{
|
||||
m_symbolStringifier = stringifier;
|
||||
}
|
||||
|
||||
private:
|
||||
SymbolStringifier m_symbolStringifier;
|
||||
};
|
||||
|
||||
class LanguageClientOutlineWidget : public TextEditor::IOutlineWidget
|
||||
@@ -153,6 +165,7 @@ LanguageClientOutlineWidget::LanguageClientOutlineWidget(Client *client,
|
||||
layout->setSpacing(0);
|
||||
layout->addWidget(Core::ItemViewFind::createSearchableWrapper(&m_view));
|
||||
setLayout(layout);
|
||||
m_model.setSymbolStringifier(m_client->symbolStringifier());
|
||||
m_view.setModel(&m_model);
|
||||
m_view.setHeaderHidden(true);
|
||||
m_view.setExpandsOnDoubleClick(false);
|
||||
@@ -295,6 +308,7 @@ OutlineComboBox::OutlineComboBox(Client *client, TextEditor::BaseTextEditor *edi
|
||||
, m_editorWidget(editor->editorWidget())
|
||||
, m_uri(DocumentUri::fromFilePath(editor->document()->filePath()))
|
||||
{
|
||||
m_model.setSymbolStringifier(client->symbolStringifier());
|
||||
setModel(&m_model);
|
||||
setMinimumContentsLength(13);
|
||||
QSizePolicy policy = sizePolicy();
|
||||
|
Reference in New Issue
Block a user