forked from qt-creator/qt-creator
ClangCodeModel: Provide diagnostics via clangd
Change-Id: Ib45a62ebe200c2b56a1bb1a66f8a92103e60d092 Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -41,8 +41,6 @@
|
|||||||
|
|
||||||
#define qCDebugIpc() qCDebug(ipcLog) << "<===="
|
#define qCDebugIpc() qCDebug(ipcLog) << "<===="
|
||||||
|
|
||||||
using namespace ClangBackEnd;
|
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
@@ -189,12 +187,12 @@ void BackendReceiver::alive()
|
|||||||
m_aliveHandler();
|
m_aliveHandler();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendReceiver::echo(const EchoMessage &message)
|
void BackendReceiver::echo(const ClangBackEnd::EchoMessage &message)
|
||||||
{
|
{
|
||||||
qCDebugIpc() << message;
|
qCDebugIpc() << message;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendReceiver::completions(const CompletionsMessage &message)
|
void BackendReceiver::completions(const ClangBackEnd::CompletionsMessage &message)
|
||||||
{
|
{
|
||||||
qCDebugIpc() << "CompletionsMessage with" << message.codeCompletions.size()
|
qCDebugIpc() << "CompletionsMessage with" << message.codeCompletions.size()
|
||||||
<< "items";
|
<< "items";
|
||||||
@@ -204,7 +202,7 @@ void BackendReceiver::completions(const CompletionsMessage &message)
|
|||||||
processor->handleAvailableCompletions(message.codeCompletions);
|
processor->handleAvailableCompletions(message.codeCompletions);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendReceiver::annotations(const AnnotationsMessage &message)
|
void BackendReceiver::annotations(const ClangBackEnd::AnnotationsMessage &message)
|
||||||
{
|
{
|
||||||
qCDebugIpc() << "AnnotationsMessage"
|
qCDebugIpc() << "AnnotationsMessage"
|
||||||
<< "for" << QFileInfo(message.fileContainer.filePath).fileName() << "with"
|
<< "for" << QFileInfo(message.fileContainer.filePath).fileName() << "with"
|
||||||
@@ -230,10 +228,10 @@ void BackendReceiver::annotations(const AnnotationsMessage &message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
CppTools::CursorInfo::Range toCursorInfoRange(const SourceRangeContainer &sourceRange)
|
CppTools::CursorInfo::Range toCursorInfoRange(const ClangBackEnd::SourceRangeContainer &sourceRange)
|
||||||
{
|
{
|
||||||
const SourceLocationContainer &start = sourceRange.start;
|
const ClangBackEnd::SourceLocationContainer &start = sourceRange.start;
|
||||||
const SourceLocationContainer &end = sourceRange.end;
|
const ClangBackEnd::SourceLocationContainer &end = sourceRange.end;
|
||||||
const int length = end.column - start.column;
|
const int length = end.column - start.column;
|
||||||
|
|
||||||
return {start.line, start.column, length};
|
return {start.line, start.column, length};
|
||||||
@@ -241,13 +239,13 @@ CppTools::CursorInfo::Range toCursorInfoRange(const SourceRangeContainer &source
|
|||||||
|
|
||||||
static
|
static
|
||||||
CppTools::CursorInfo toCursorInfo(const CppTools::SemanticInfo::LocalUseMap &localUses,
|
CppTools::CursorInfo toCursorInfo(const CppTools::SemanticInfo::LocalUseMap &localUses,
|
||||||
const ReferencesMessage &message)
|
const ClangBackEnd::ReferencesMessage &message)
|
||||||
{
|
{
|
||||||
CppTools::CursorInfo result;
|
CppTools::CursorInfo result;
|
||||||
const QVector<SourceRangeContainer> &references = message.references;
|
const QVector<ClangBackEnd::SourceRangeContainer> &references = message.references;
|
||||||
|
|
||||||
result.areUseRangesForLocalVariable = message.isLocalVariable;
|
result.areUseRangesForLocalVariable = message.isLocalVariable;
|
||||||
for (const SourceRangeContainer &reference : references)
|
for (const ClangBackEnd::SourceRangeContainer &reference : references)
|
||||||
result.useRanges.append(toCursorInfoRange(reference));
|
result.useRanges.append(toCursorInfoRange(reference));
|
||||||
|
|
||||||
result.useRanges.reserve(references.size());
|
result.useRanges.reserve(references.size());
|
||||||
@@ -257,13 +255,13 @@ CppTools::CursorInfo toCursorInfo(const CppTools::SemanticInfo::LocalUseMap &loc
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message)
|
CppTools::SymbolInfo toSymbolInfo(const ClangBackEnd::FollowSymbolMessage &message)
|
||||||
{
|
{
|
||||||
CppTools::SymbolInfo result;
|
CppTools::SymbolInfo result;
|
||||||
const SourceRangeContainer &range = message.result.range;
|
const ClangBackEnd::SourceRangeContainer &range = message.result.range;
|
||||||
|
|
||||||
const SourceLocationContainer &start = range.start;
|
const ClangBackEnd::SourceLocationContainer &start = range.start;
|
||||||
const SourceLocationContainer &end = range.end;
|
const ClangBackEnd::SourceLocationContainer &end = range.end;
|
||||||
result.startLine = start.line;
|
result.startLine = start.line;
|
||||||
result.startColumn = start.column;
|
result.startColumn = start.column;
|
||||||
result.endLine = end.line;
|
result.endLine = end.line;
|
||||||
@@ -275,7 +273,7 @@ CppTools::SymbolInfo toSymbolInfo(const FollowSymbolMessage &message)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendReceiver::references(const ReferencesMessage &message)
|
void BackendReceiver::references(const ClangBackEnd::ReferencesMessage &message)
|
||||||
{
|
{
|
||||||
qCDebugIpc() << "ReferencesMessage with"
|
qCDebugIpc() << "ReferencesMessage with"
|
||||||
<< message.references.size() << "references";
|
<< message.references.size() << "references";
|
||||||
@@ -292,22 +290,22 @@ void BackendReceiver::references(const ReferencesMessage &message)
|
|||||||
futureInterface.reportFinished();
|
futureInterface.reportFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
static Core::HelpItem::Category toHelpItemCategory(ToolTipInfo::QdocCategory category)
|
static Core::HelpItem::Category toHelpItemCategory(ClangBackEnd::ToolTipInfo::QdocCategory category)
|
||||||
{
|
{
|
||||||
switch (category) {
|
switch (category) {
|
||||||
case ToolTipInfo::Unknown:
|
case ClangBackEnd::ToolTipInfo::Unknown:
|
||||||
return Core::HelpItem::Unknown;
|
return Core::HelpItem::Unknown;
|
||||||
case ToolTipInfo::ClassOrNamespace:
|
case ClangBackEnd::ToolTipInfo::ClassOrNamespace:
|
||||||
return Core::HelpItem::ClassOrNamespace;
|
return Core::HelpItem::ClassOrNamespace;
|
||||||
case ToolTipInfo::Enum:
|
case ClangBackEnd::ToolTipInfo::Enum:
|
||||||
return Core::HelpItem::Enum;
|
return Core::HelpItem::Enum;
|
||||||
case ToolTipInfo::Typedef:
|
case ClangBackEnd::ToolTipInfo::Typedef:
|
||||||
return Core::HelpItem::Typedef;
|
return Core::HelpItem::Typedef;
|
||||||
case ToolTipInfo::Macro:
|
case ClangBackEnd::ToolTipInfo::Macro:
|
||||||
return Core::HelpItem::Macro;
|
return Core::HelpItem::Macro;
|
||||||
case ToolTipInfo::Brief:
|
case ClangBackEnd::ToolTipInfo::Brief:
|
||||||
return Core::HelpItem::Brief;
|
return Core::HelpItem::Brief;
|
||||||
case ToolTipInfo::Function:
|
case ClangBackEnd::ToolTipInfo::Function:
|
||||||
return Core::HelpItem::Function;
|
return Core::HelpItem::Function;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,11 +323,11 @@ static QStringList toStringList(const Utf8StringVector &utf8StringVector)
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CppTools::ToolTipInfo toToolTipInfo(const ToolTipMessage &message)
|
static CppTools::ToolTipInfo toToolTipInfo(const ClangBackEnd::ToolTipMessage &message)
|
||||||
{
|
{
|
||||||
CppTools::ToolTipInfo info;
|
CppTools::ToolTipInfo info;
|
||||||
|
|
||||||
const ToolTipInfo &backendInfo = message.toolTipInfo;
|
const ClangBackEnd::ToolTipInfo &backendInfo = message.toolTipInfo;
|
||||||
|
|
||||||
info.text = backendInfo.text;
|
info.text = backendInfo.text;
|
||||||
info.briefComment = backendInfo.briefComment;
|
info.briefComment = backendInfo.briefComment;
|
||||||
@@ -343,7 +341,7 @@ static CppTools::ToolTipInfo toToolTipInfo(const ToolTipMessage &message)
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BackendReceiver::tooltip(const ToolTipMessage &message)
|
void BackendReceiver::tooltip(const ClangBackEnd::ToolTipMessage &message)
|
||||||
{
|
{
|
||||||
qCDebugIpc() << "ToolTipMessage" << message.toolTipInfo.text;
|
qCDebugIpc() << "ToolTipMessage" << message.toolTipInfo.text;
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
|
|
||||||
#include "clangdclient.h"
|
#include "clangdclient.h"
|
||||||
|
|
||||||
|
#include "clangdiagnosticmanager.h"
|
||||||
|
#include "clangtextmark.h"
|
||||||
|
|
||||||
#include <clangsupport/sourcelocationscontainer.h>
|
#include <clangsupport/sourcelocationscontainer.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/find/searchresultitem.h>
|
#include <coreplugin/find/searchresultitem.h>
|
||||||
@@ -37,6 +40,7 @@
|
|||||||
#include <cpptools/cppvirtualfunctionassistprovider.h>
|
#include <cpptools/cppvirtualfunctionassistprovider.h>
|
||||||
#include <cpptools/cppvirtualfunctionproposalitem.h>
|
#include <cpptools/cppvirtualfunctionproposalitem.h>
|
||||||
#include <languageclient/languageclientinterface.h>
|
#include <languageclient/languageclientinterface.h>
|
||||||
|
#include <languageclient/languageclientutils.h>
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/projecttree.h>
|
#include <projectexplorer/projecttree.h>
|
||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
@@ -604,6 +608,23 @@ public:
|
|||||||
const int revision;
|
const int revision;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DiagnosticsCapabilities : public JsonObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using JsonObject::JsonObject;
|
||||||
|
void enableCategorySupport() { insert("categorySupport", true); }
|
||||||
|
void enableCodeActionsInline() {insert("codeActionsInline", true);}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ClangdTextDocumentClientCapabilities : public TextDocumentClientCapabilities
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using TextDocumentClientCapabilities::TextDocumentClientCapabilities;
|
||||||
|
|
||||||
|
|
||||||
|
void setPublishDiagnostics(const DiagnosticsCapabilities &caps)
|
||||||
|
{ insert("publishDiagnostics", caps); }
|
||||||
|
};
|
||||||
|
|
||||||
class ClangdClient::Private
|
class ClangdClient::Private
|
||||||
{
|
{
|
||||||
@@ -650,12 +671,30 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
|
|||||||
langFilter.mimeTypes = QStringList{"text/x-chdr", "text/x-csrc",
|
langFilter.mimeTypes = QStringList{"text/x-chdr", "text/x-csrc",
|
||||||
"text/x-c++hdr", "text/x-c++src", "text/x-objc++src", "text/x-objcsrc"};
|
"text/x-c++hdr", "text/x-c++src", "text/x-objc++src", "text/x-objcsrc"};
|
||||||
setSupportedLanguage(langFilter);
|
setSupportedLanguage(langFilter);
|
||||||
LanguageServerProtocol::ClientCapabilities caps = Client::defaultClientCapabilities();
|
setActivateDocumentAutomatically(true);
|
||||||
|
ClientCapabilities caps = Client::defaultClientCapabilities();
|
||||||
|
Utils::optional<TextDocumentClientCapabilities> textCaps = caps.textDocument();
|
||||||
|
if (textCaps) {
|
||||||
|
ClangdTextDocumentClientCapabilities clangdTextCaps(*textCaps);
|
||||||
|
clangdTextCaps.clearCompletion();
|
||||||
|
clangdTextCaps.clearDocumentHighlight();
|
||||||
|
DiagnosticsCapabilities diagnostics;
|
||||||
|
diagnostics.enableCategorySupport();
|
||||||
|
diagnostics.enableCodeActionsInline();
|
||||||
|
clangdTextCaps.setPublishDiagnostics(diagnostics);
|
||||||
|
caps.setTextDocument(clangdTextCaps);
|
||||||
|
}
|
||||||
caps.clearExperimental();
|
caps.clearExperimental();
|
||||||
setClientCapabilities(caps);
|
setClientCapabilities(caps);
|
||||||
setLocatorsEnabled(false);
|
setLocatorsEnabled(false);
|
||||||
setProgressTitleForToken(indexingToken(), tr("Parsing C/C++ Files (clangd)"));
|
setProgressTitleForToken(indexingToken(), tr("Parsing C/C++ Files (clangd)"));
|
||||||
setCurrentProject(project);
|
setCurrentProject(project);
|
||||||
|
|
||||||
|
const auto textMarkCreator = [this](const Utils::FilePath &filePath,
|
||||||
|
const Diagnostic &diag) { return new ClangdTextMark(filePath, diag, this); };
|
||||||
|
const auto hideDiagsHandler = []{ ClangDiagnosticManager::clearTaskHubIssues(); };
|
||||||
|
setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler);
|
||||||
|
|
||||||
connect(this, &Client::workDone, this, [this, project](const ProgressToken &token) {
|
connect(this, &Client::workDone, this, [this, project](const ProgressToken &token) {
|
||||||
const QString * const val = Utils::get_if<QString>(&token);
|
const QString * const val = Utils::get_if<QString>(&token);
|
||||||
if (val && *val == indexingToken()) {
|
if (val && *val == indexingToken()) {
|
||||||
@@ -791,6 +830,17 @@ void ClangdClient::findUsages(TextEditor::TextDocument *document, const QTextCur
|
|||||||
|
|
||||||
void ClangdClient::enableTesting() { d->isTesting = true; }
|
void ClangdClient::enableTesting() { d->isTesting = true; }
|
||||||
|
|
||||||
|
void ClangdClient::handleDiagnostics(const PublishDiagnosticsParams ¶ms)
|
||||||
|
{
|
||||||
|
const DocumentUri &uri = params.uri();
|
||||||
|
Client::handleDiagnostics(params);
|
||||||
|
for (const Diagnostic &diagnostic : params.diagnostics()) {
|
||||||
|
const ClangdDiagnostic clangdDiagnostic(diagnostic);
|
||||||
|
for (const CodeAction &action : clangdDiagnostic.codeActions().value_or(QList<CodeAction>{}))
|
||||||
|
LanguageClient::updateCodeActionRefactoringMarker(this, action, uri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QVersionNumber ClangdClient::versionNumber() const
|
QVersionNumber ClangdClient::versionNumber() const
|
||||||
{
|
{
|
||||||
if (d->versionNumber)
|
if (d->versionNumber)
|
||||||
@@ -1506,6 +1556,16 @@ TextEditor::IAssistProcessor *ClangdClient::VirtualFunctionAssistProvider::creat
|
|||||||
= new VirtualFunctionAssistProcessor(m_data);
|
= new VirtualFunctionAssistProcessor(m_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Utils::optional<QList<CodeAction> > ClangdDiagnostic::codeActions() const
|
||||||
|
{
|
||||||
|
return optionalArray<LanguageServerProtocol::CodeAction>("codeActions");
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ClangdDiagnostic::category() const
|
||||||
|
{
|
||||||
|
return typedValue<QString>("category");
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ signals:
|
|||||||
void findUsagesDone();
|
void findUsagesDone();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void handleDiagnostics(const LanguageServerProtocol::PublishDiagnosticsParams ¶ms) override;
|
||||||
|
|
||||||
class Private;
|
class Private;
|
||||||
class FollowSymbolData;
|
class FollowSymbolData;
|
||||||
class VirtualFunctionAssistProcessor;
|
class VirtualFunctionAssistProcessor;
|
||||||
@@ -85,5 +87,13 @@ private:
|
|||||||
Private * const d;
|
Private * const d;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ClangdDiagnostic : public LanguageServerProtocol::Diagnostic
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Diagnostic::Diagnostic;
|
||||||
|
Utils::optional<QList<LanguageServerProtocol::CodeAction>> codeActions() const;
|
||||||
|
QString category() const;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
|||||||
@@ -298,7 +298,8 @@ void ClangDiagnosticManager::generateFixItAvailableMarkers()
|
|||||||
addFixItAvailableMarker(m_errorDiagnostics, lineNumbersWithFixItMarker);
|
addFixItAvailableMarker(m_errorDiagnostics, lineNumbersWithFixItMarker);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addTask(const ClangBackEnd::DiagnosticContainer &diagnostic, bool isChild = false)
|
void ClangDiagnosticManager::addTask(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||||
|
bool isChild)
|
||||||
{
|
{
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
using ::Utils::FilePath;
|
using ::Utils::FilePath;
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ public:
|
|||||||
static void clearTaskHubIssues();
|
static void clearTaskHubIssues();
|
||||||
void generateTaskHubIssues();
|
void generateTaskHubIssues();
|
||||||
|
|
||||||
|
static void addTask(const ClangBackEnd::DiagnosticContainer &diagnostic, bool isChild = false);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void cleanMarks();
|
void cleanMarks();
|
||||||
QString filePath() const;
|
QString filePath() const;
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
QWidget *createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
QWidget *createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
const ClangDiagnosticManager *diagMgr)
|
const std::function<bool()> &canApplyFixIt)
|
||||||
{
|
{
|
||||||
const QString text = htmlText(diagnostics);
|
const QString text = htmlText(diagnostics);
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ public:
|
|||||||
const TargetIdToDiagnosticTable table = m_targetIdsToDiagnostics;
|
const TargetIdToDiagnosticTable table = m_targetIdsToDiagnostics;
|
||||||
const bool hideToolTipAfterLinkActivation = m_displayHints.hideTooltipAfterLinkActivation;
|
const bool hideToolTipAfterLinkActivation = m_displayHints.hideTooltipAfterLinkActivation;
|
||||||
QObject::connect(label, &QLabel::linkActivated, [table, hideToolTipAfterLinkActivation,
|
QObject::connect(label, &QLabel::linkActivated, [table, hideToolTipAfterLinkActivation,
|
||||||
diagMgr](const QString &action) {
|
canApplyFixIt](const QString &action) {
|
||||||
const ClangBackEnd::DiagnosticContainer diagnostic = table.value(action);
|
const ClangBackEnd::DiagnosticContainer diagnostic = table.value(action);
|
||||||
|
|
||||||
if (diagnostic == ClangBackEnd::DiagnosticContainer())
|
if (diagnostic == ClangBackEnd::DiagnosticContainer())
|
||||||
@@ -141,10 +141,8 @@ public:
|
|||||||
else if (action.startsWith(LINK_ACTION_GOTO_LOCATION)) {
|
else if (action.startsWith(LINK_ACTION_GOTO_LOCATION)) {
|
||||||
openEditorAt(diagnostic);
|
openEditorAt(diagnostic);
|
||||||
} else if (action.startsWith(LINK_ACTION_APPLY_FIX)) {
|
} else if (action.startsWith(LINK_ACTION_APPLY_FIX)) {
|
||||||
if (diagMgr && !diagMgr->diagnosticsInvalidated()
|
if (canApplyFixIt && canApplyFixIt())
|
||||||
&& diagMgr->diagnosticsWithFixIts().contains(diagnostic)) {
|
|
||||||
applyFixit(diagnostic);
|
applyFixit(diagnostic);
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
QTC_CHECK(!"Link target cannot be handled.");
|
QTC_CHECK(!"Link target cannot be handled.");
|
||||||
}
|
}
|
||||||
@@ -368,14 +366,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
WidgetFromDiagnostics::DisplayHints toHints(const ClangDiagnosticWidget::Destination &destination,
|
WidgetFromDiagnostics::DisplayHints toHints(const ClangDiagnosticWidget::Destination &destination,
|
||||||
const ClangDiagnosticManager *diagMgr = nullptr)
|
const std::function<bool()> &canApplyFixIt)
|
||||||
{
|
{
|
||||||
WidgetFromDiagnostics::DisplayHints hints;
|
WidgetFromDiagnostics::DisplayHints hints;
|
||||||
|
|
||||||
if (destination == ClangDiagnosticWidget::ToolTip) {
|
if (destination == ClangDiagnosticWidget::ToolTip) {
|
||||||
hints.showCategoryAndEnableOption = true;
|
hints.showCategoryAndEnableOption = true;
|
||||||
hints.showFileNameInMainDiagnostic = false;
|
hints.showFileNameInMainDiagnostic = false;
|
||||||
hints.enableClickableFixits = diagMgr && !diagMgr->diagnosticsInvalidated();
|
hints.enableClickableFixits = canApplyFixIt && canApplyFixIt();
|
||||||
hints.limitWidth = true;
|
hints.limitWidth = true;
|
||||||
hints.hideTooltipAfterLinkActivation = true;
|
hints.hideTooltipAfterLinkActivation = true;
|
||||||
hints.allowTextSelection = false;
|
hints.allowTextSelection = false;
|
||||||
@@ -398,7 +396,7 @@ QString ClangDiagnosticWidget::createText(
|
|||||||
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
const ClangDiagnosticWidget::Destination &destination)
|
const ClangDiagnosticWidget::Destination &destination)
|
||||||
{
|
{
|
||||||
const QString htmlText = WidgetFromDiagnostics(toHints(destination)).htmlText(diagnostics);
|
const QString htmlText = WidgetFromDiagnostics(toHints(destination, {})).htmlText(diagnostics);
|
||||||
|
|
||||||
QTextDocument document;
|
QTextDocument document;
|
||||||
document.setHtml(htmlText);
|
document.setHtml(htmlText);
|
||||||
@@ -413,9 +411,10 @@ QString ClangDiagnosticWidget::createText(
|
|||||||
}
|
}
|
||||||
|
|
||||||
QWidget *ClangDiagnosticWidget::createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
QWidget *ClangDiagnosticWidget::createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
const Destination &destination, const ClangDiagnosticManager *diagMgr)
|
const Destination &destination, const std::function<bool()> &canApplyFixIt)
|
||||||
{
|
{
|
||||||
return WidgetFromDiagnostics(toHints(destination, diagMgr)).createWidget(diagnostics, diagMgr);
|
return WidgetFromDiagnostics(toHints(destination, canApplyFixIt))
|
||||||
|
.createWidget(diagnostics, canApplyFixIt);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include <clangsupport/diagnosticcontainer.h>
|
#include <clangsupport/diagnosticcontainer.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QLayout;
|
class QLayout;
|
||||||
class QWidget;
|
class QWidget;
|
||||||
@@ -43,9 +45,10 @@ public:
|
|||||||
static QString createText(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
static QString createText(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
const Destination &destination);
|
const Destination &destination);
|
||||||
|
|
||||||
|
|
||||||
static QWidget *createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
static QWidget *createWidget(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||||
const Destination &destination,
|
const Destination &destination,
|
||||||
const ClangDiagnosticManager *diagMgr = nullptr);
|
const std::function<bool()> &canApplyFixIt);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ void ClangEditorDocumentProcessor::updateCodeWarnings(
|
|||||||
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic,
|
const ClangBackEnd::DiagnosticContainer &firstHeaderErrorDiagnostic,
|
||||||
uint documentRevision)
|
uint documentRevision)
|
||||||
{
|
{
|
||||||
|
if (ClangModelManagerSupport::instance()->clientForFile(m_document.filePath()))
|
||||||
|
return;
|
||||||
|
|
||||||
if (documentRevision == revision()) {
|
if (documentRevision == revision()) {
|
||||||
if (m_invalidationState == InvalidationState::Scheduled)
|
if (m_invalidationState == InvalidationState::Scheduled)
|
||||||
m_invalidationState = InvalidationState::Canceled;
|
m_invalidationState = InvalidationState::Canceled;
|
||||||
@@ -489,7 +492,7 @@ ClangEditorDocumentProcessor::creatorForHeaderErrorDiagnosticWidget(
|
|||||||
vbox->setSpacing(2);
|
vbox->setSpacing(2);
|
||||||
|
|
||||||
vbox->addWidget(ClangDiagnosticWidget::createWidget({firstHeaderErrorDiagnostic},
|
vbox->addWidget(ClangDiagnosticWidget::createWidget({firstHeaderErrorDiagnostic},
|
||||||
ClangDiagnosticWidget::InfoBar));
|
ClangDiagnosticWidget::InfoBar, {}));
|
||||||
|
|
||||||
auto widget = new QWidget;
|
auto widget = new QWidget;
|
||||||
widget->setLayout(vbox);
|
widget->setLayout(vbox);
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "clangtextmark.h"
|
#include "clangtextmark.h"
|
||||||
|
|
||||||
#include "clangconstants.h"
|
#include "clangconstants.h"
|
||||||
|
#include "clangdclient.h"
|
||||||
#include "clangdiagnostictooltipwidget.h"
|
#include "clangdiagnostictooltipwidget.h"
|
||||||
#include "clangeditordocumentprocessor.h"
|
#include "clangeditordocumentprocessor.h"
|
||||||
#include "clangmodelmanagersupport.h"
|
#include "clangmodelmanagersupport.h"
|
||||||
@@ -47,10 +48,13 @@
|
|||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
#include <QLayout>
|
#include <QLayout>
|
||||||
|
#include <QPointer>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
using namespace CppTools;
|
using namespace CppTools;
|
||||||
using namespace ClangCodeModel::Internal;
|
using namespace ClangCodeModel::Internal;
|
||||||
|
using namespace LanguageClient;
|
||||||
|
using namespace LanguageServerProtocol;
|
||||||
using namespace Utils;
|
using namespace Utils;
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
@@ -272,10 +276,13 @@ void ClangTextMark::updateIcon(bool valid)
|
|||||||
|
|
||||||
bool ClangTextMark::addToolTipContent(QLayout *target) const
|
bool ClangTextMark::addToolTipContent(QLayout *target) const
|
||||||
{
|
{
|
||||||
|
const auto canApplyFixIt = [diag = m_diagnostic, diagMgr = m_diagMgr, c = color()] {
|
||||||
|
return c != Utils::Theme::Color::IconsDisabledColor
|
||||||
|
&& !diagMgr->diagnosticsInvalidated()
|
||||||
|
&& diagMgr->diagnosticsWithFixIts().contains(diag);
|
||||||
|
};
|
||||||
QWidget *widget = ClangDiagnosticWidget::createWidget(
|
QWidget *widget = ClangDiagnosticWidget::createWidget(
|
||||||
{m_diagnostic}, ClangDiagnosticWidget::ToolTip,
|
{m_diagnostic}, ClangDiagnosticWidget::ToolTip, canApplyFixIt);
|
||||||
color() == Utils::Theme::Color::IconsDisabledColor ? nullptr : m_diagMgr);
|
|
||||||
target->addWidget(widget);
|
target->addWidget(widget);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -287,5 +294,113 @@ void ClangTextMark::removedFromEditor()
|
|||||||
m_removedFromEditorHandler(this);
|
m_removedFromEditorHandler(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClangBackEnd::DiagnosticSeverity convertSeverity(DiagnosticSeverity src)
|
||||||
|
{
|
||||||
|
if (src == DiagnosticSeverity::Error)
|
||||||
|
return ClangBackEnd::DiagnosticSeverity::Error;
|
||||||
|
if (src == DiagnosticSeverity::Warning)
|
||||||
|
return ClangBackEnd::DiagnosticSeverity::Warning;
|
||||||
|
return ClangBackEnd::DiagnosticSeverity::Note;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangBackEnd::SourceRangeContainer convertRange(const FilePath &filePath, const Range &src)
|
||||||
|
{
|
||||||
|
const ClangBackEnd::SourceLocationContainer start(filePath.toString(), src.start().line() + 1,
|
||||||
|
src.start().character() + 1);
|
||||||
|
const ClangBackEnd::SourceLocationContainer end(filePath.toString(), src.end().line() + 1,
|
||||||
|
src.end().character() + 1);
|
||||||
|
return ClangBackEnd::SourceRangeContainer(start, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangBackEnd::DiagnosticContainer convertDiagnostic(const ClangdDiagnostic &src,
|
||||||
|
const FilePath &filePath)
|
||||||
|
{
|
||||||
|
ClangBackEnd::DiagnosticContainer target;
|
||||||
|
target.ranges.append(convertRange(filePath, src.range()));
|
||||||
|
target.location = target.ranges.first().start;
|
||||||
|
target.text = src.message();
|
||||||
|
target.category = src.category();
|
||||||
|
if (src.severity())
|
||||||
|
target.severity = convertSeverity(*src.severity());
|
||||||
|
const Diagnostic::Code code = src.code().value_or(Diagnostic::Code());
|
||||||
|
const QString * const codeString = Utils::get_if<QString>(&code);
|
||||||
|
if (codeString && codeString->startsWith("-W"))
|
||||||
|
target.enableOption = *codeString;
|
||||||
|
for (const CodeAction &codeAction : src.codeActions().value_or(QList<CodeAction>())) {
|
||||||
|
const Utils::optional<WorkspaceEdit> edit = codeAction.edit();
|
||||||
|
if (!edit)
|
||||||
|
continue;
|
||||||
|
const Utils::optional<WorkspaceEdit::Changes> changes = edit->changes();
|
||||||
|
if (!changes)
|
||||||
|
continue;
|
||||||
|
for (auto it = changes->cbegin(); it != changes->cend(); ++it) {
|
||||||
|
for (const TextEdit &textEdit : it.value()) {
|
||||||
|
target.fixIts << ClangBackEnd::FixItContainer(textEdit.newText(),
|
||||||
|
convertRange(it.key().toFilePath(), textEdit.range()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClangdTextMark::ClangdTextMark(const FilePath &filePath,
|
||||||
|
const Diagnostic &diagnostic,
|
||||||
|
const Client *client)
|
||||||
|
: TextEditor::TextMark(filePath, int(diagnostic.range().start().line() + 1), client->id())
|
||||||
|
, m_lspDiagnostic(diagnostic)
|
||||||
|
, m_diagnostic(convertDiagnostic(ClangdDiagnostic(diagnostic), filePath))
|
||||||
|
, m_client(client)
|
||||||
|
{
|
||||||
|
setSettingsPage(CppTools::Constants::CPP_CODE_MODEL_SETTINGS_ID);
|
||||||
|
|
||||||
|
const bool isError = diagnostic.severity()
|
||||||
|
&& *diagnostic.severity() == DiagnosticSeverity::Error;
|
||||||
|
setDefaultToolTip(isError ? tr("Code Model Error") : tr("Code Model Warning"));
|
||||||
|
setPriority(isError ? TextEditor::TextMark::HighPriority
|
||||||
|
: TextEditor::TextMark::NormalPriority);
|
||||||
|
setIcon(isError ? Icons::CODEMODEL_ERROR.icon() : Icons::CODEMODEL_WARNING.icon());
|
||||||
|
setLineAnnotation(diagnostic.message());
|
||||||
|
setColor(isError ? Theme::CodeModel_Error_TextMarkColor
|
||||||
|
: Theme::CodeModel_Warning_TextMarkColor);
|
||||||
|
|
||||||
|
// Copy to clipboard action
|
||||||
|
QVector<QAction *> actions;
|
||||||
|
QAction *action = new QAction();
|
||||||
|
action->setIcon(QIcon::fromTheme("edit-copy", Icons::COPY.icon()));
|
||||||
|
action->setToolTip(tr("Clang Code Model Marks", "Copy to Clipboard"));
|
||||||
|
QObject::connect(action, &QAction::triggered, [diag = m_diagnostic]() {
|
||||||
|
const QString text = ClangDiagnosticWidget::createText({diag},
|
||||||
|
ClangDiagnosticWidget::InfoBar);
|
||||||
|
QApplication::clipboard()->setText(text, QClipboard::Clipboard);
|
||||||
|
});
|
||||||
|
actions << action;
|
||||||
|
|
||||||
|
// Remove diagnostic warning action
|
||||||
|
ProjectExplorer::Project *project = projectForCurrentEditor();
|
||||||
|
if (project && isDiagnosticConfigChangable(project, m_diagnostic)) {
|
||||||
|
action = new QAction();
|
||||||
|
action->setIcon(Icons::BROKEN.icon());
|
||||||
|
action->setToolTip(tr("Disable Diagnostic in Current Project"));
|
||||||
|
QObject::connect(action, &QAction::triggered, [diag = m_diagnostic]() {
|
||||||
|
disableDiagnosticInCurrentProjectConfig(diag);
|
||||||
|
});
|
||||||
|
actions << action;
|
||||||
|
}
|
||||||
|
|
||||||
|
setActions(actions);
|
||||||
|
|
||||||
|
ClangDiagnosticManager::addTask(m_diagnostic);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangdTextMark::addToolTipContent(QLayout *target) const
|
||||||
|
{
|
||||||
|
const auto canApplyFixIt = [c = QPointer(m_client), diag = m_lspDiagnostic, fp = fileName()] {
|
||||||
|
return c && c->reachable() && c->hasDiagnostic(DocumentUri::fromFilePath(fp), diag);
|
||||||
|
};
|
||||||
|
target->addWidget(ClangDiagnosticWidget::createWidget({m_diagnostic},
|
||||||
|
ClangDiagnosticWidget::ToolTip, canApplyFixIt));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
|||||||
@@ -28,10 +28,14 @@
|
|||||||
#include <clangsupport_global.h>
|
#include <clangsupport_global.h>
|
||||||
#include <clangsupport/diagnosticcontainer.h>
|
#include <clangsupport/diagnosticcontainer.h>
|
||||||
|
|
||||||
|
#include <languageserverprotocol/lsptypes.h>
|
||||||
|
|
||||||
#include <texteditor/textmark.h>
|
#include <texteditor/textmark.h>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
namespace LanguageClient { class Client; }
|
||||||
|
|
||||||
namespace ClangCodeModel {
|
namespace ClangCodeModel {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
class ClangDiagnosticManager;
|
class ClangDiagnosticManager;
|
||||||
@@ -60,5 +64,21 @@ private:
|
|||||||
const ClangDiagnosticManager * const m_diagMgr;
|
const ClangDiagnosticManager * const m_diagMgr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ClangdTextMark : public TextEditor::TextMark
|
||||||
|
{
|
||||||
|
Q_DECLARE_TR_FUNCTIONS(ClangdTextMark)
|
||||||
|
public:
|
||||||
|
ClangdTextMark(const ::Utils::FilePath &filePath,
|
||||||
|
const LanguageServerProtocol::Diagnostic &diagnostic,
|
||||||
|
const LanguageClient::Client *client);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool addToolTipContent(QLayout *target) const override;
|
||||||
|
|
||||||
|
const LanguageServerProtocol::Diagnostic m_lspDiagnostic;
|
||||||
|
const ClangBackEnd::DiagnosticContainer m_diagnostic;
|
||||||
|
const LanguageClient::Client * const m_client;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace ClangCodeModel
|
} // namespace ClangCodeModel
|
||||||
|
|||||||
@@ -52,7 +52,6 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
|
|
||||||
using namespace ClangBackEnd;
|
|
||||||
using namespace ClangCodeModel;
|
using namespace ClangCodeModel;
|
||||||
using namespace ClangCodeModel::Internal;
|
using namespace ClangCodeModel::Internal;
|
||||||
|
|
||||||
|
|||||||
@@ -991,6 +991,18 @@ QList<Diagnostic> Client::diagnosticsAt(const DocumentUri &uri, const QTextCurso
|
|||||||
return m_diagnosticManager.diagnosticsAt(uri, cursor);
|
return m_diagnosticManager.diagnosticsAt(uri, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Client::hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
|
const LanguageServerProtocol::Diagnostic &diag) const
|
||||||
|
{
|
||||||
|
return m_diagnosticManager.hasDiagnostic(uri, documentForFilePath(uri.toFilePath()), diag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Client::setDiagnosticsHandlers(const TextMarkCreator &textMarkCreator,
|
||||||
|
const HideDiagnosticsHandler &hideHandler)
|
||||||
|
{
|
||||||
|
m_diagnosticManager.setDiagnosticsHandlers(textMarkCreator, hideHandler);
|
||||||
|
}
|
||||||
|
|
||||||
void Client::start()
|
void Client::start()
|
||||||
{
|
{
|
||||||
if (m_clientInterface->start())
|
if (m_clientInterface->start())
|
||||||
|
|||||||
@@ -170,6 +170,10 @@ public:
|
|||||||
QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(
|
QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(
|
||||||
const LanguageServerProtocol::DocumentUri &uri,
|
const LanguageServerProtocol::DocumentUri &uri,
|
||||||
const QTextCursor &cursor) const;
|
const QTextCursor &cursor) const;
|
||||||
|
bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
|
const LanguageServerProtocol::Diagnostic &diag) const;
|
||||||
|
void setDiagnosticsHandlers(const TextMarkCreator &textMarkCreator,
|
||||||
|
const HideDiagnosticsHandler &hideHandler);
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
void log(const QString &message) const;
|
void log(const QString &message) const;
|
||||||
@@ -189,6 +193,7 @@ protected:
|
|||||||
void setProgressTitleForToken(const LanguageServerProtocol::ProgressToken &token,
|
void setProgressTitleForToken(const LanguageServerProtocol::ProgressToken &token,
|
||||||
const QString &message);
|
const QString &message);
|
||||||
void handleMessage(const LanguageServerProtocol::BaseMessage &message);
|
void handleMessage(const LanguageServerProtocol::BaseMessage &message);
|
||||||
|
virtual void handleDiagnostics(const LanguageServerProtocol::PublishDiagnosticsParams ¶ms);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void handleResponse(const LanguageServerProtocol::MessageId &id, const QByteArray &content,
|
void handleResponse(const LanguageServerProtocol::MessageId &id, const QByteArray &content,
|
||||||
@@ -196,7 +201,6 @@ private:
|
|||||||
void handleMethod(const QString &method, const LanguageServerProtocol::MessageId &id,
|
void handleMethod(const QString &method, const LanguageServerProtocol::MessageId &id,
|
||||||
const LanguageServerProtocol::IContent *content);
|
const LanguageServerProtocol::IContent *content);
|
||||||
|
|
||||||
void handleDiagnostics(const LanguageServerProtocol::PublishDiagnosticsParams ¶ms);
|
|
||||||
void handleSemanticHighlight(const LanguageServerProtocol::SemanticHighlightingParams ¶ms);
|
void handleSemanticHighlight(const LanguageServerProtocol::SemanticHighlightingParams ¶ms);
|
||||||
|
|
||||||
void initializeCallback(const LanguageServerProtocol::InitializeRequest::Response &initResponse);
|
void initializeCallback(const LanguageServerProtocol::InitializeRequest::Response &initResponse);
|
||||||
|
|||||||
@@ -91,6 +91,8 @@ void DiagnosticManager::hideDiagnostics(TextDocument *doc)
|
|||||||
if (!doc)
|
if (!doc)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (m_hideHandler)
|
||||||
|
m_hideHandler();
|
||||||
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc))
|
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc))
|
||||||
editor->editorWidget()->setExtraSelections(TextEditorWidget::CodeWarningsSelection, {});
|
editor->editorWidget()->setExtraSelections(TextEditorWidget::CodeWarningsSelection, {});
|
||||||
qDeleteAll(Utils::filtered(doc->marks(), Utils::equal(&TextMark::category, m_clientId)));
|
qDeleteAll(Utils::filtered(doc->marks(), Utils::equal(&TextMark::category, m_clientId)));
|
||||||
@@ -127,6 +129,12 @@ void DiagnosticManager::showDiagnostics(const DocumentUri &uri, int version)
|
|||||||
const auto icon = QIcon::fromTheme("edit-copy", Utils::Icons::COPY.icon());
|
const auto icon = QIcon::fromTheme("edit-copy", Utils::Icons::COPY.icon());
|
||||||
const QString tooltip = tr("Copy to Clipboard");
|
const QString tooltip = tr("Copy to Clipboard");
|
||||||
for (const Diagnostic &diagnostic : versionedDiagnostics.diagnostics) {
|
for (const Diagnostic &diagnostic : versionedDiagnostics.diagnostics) {
|
||||||
|
extraSelections << toDiagnosticsSelections(diagnostic, doc->document());
|
||||||
|
if (m_textMarkCreator) {
|
||||||
|
doc->addMark(m_textMarkCreator(filePath, diagnostic));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
QAction *action = new QAction();
|
QAction *action = new QAction();
|
||||||
action->setIcon(icon);
|
action->setIcon(icon);
|
||||||
action->setToolTip(tooltip);
|
action->setToolTip(tooltip);
|
||||||
@@ -137,7 +145,6 @@ void DiagnosticManager::showDiagnostics(const DocumentUri &uri, int version)
|
|||||||
mark->setActions({action});
|
mark->setActions({action});
|
||||||
|
|
||||||
doc->addMark(mark);
|
doc->addMark(mark);
|
||||||
extraSelections << toDiagnosticsSelections(diagnostic, doc->document());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,4 +175,26 @@ QList<Diagnostic> DiagnosticManager::diagnosticsAt(const DocumentUri &uri,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DiagnosticManager::hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
|
const TextDocument *doc,
|
||||||
|
const LanguageServerProtocol::Diagnostic &diag) const
|
||||||
|
{
|
||||||
|
if (!doc)
|
||||||
|
return false;
|
||||||
|
const auto it = m_diagnostics.find(uri);
|
||||||
|
if (it == m_diagnostics.end())
|
||||||
|
return {};
|
||||||
|
const int revision = doc->document()->revision();
|
||||||
|
if (revision != it->version.value_or(revision))
|
||||||
|
return false;
|
||||||
|
return it->diagnostics.contains(diag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiagnosticManager::setDiagnosticsHandlers(const TextMarkCreator &textMarkCreator,
|
||||||
|
const HideDiagnosticsHandler &removalHandler)
|
||||||
|
{
|
||||||
|
m_textMarkCreator = textMarkCreator;
|
||||||
|
m_hideHandler = removalHandler;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace LanguageClient
|
} // namespace LanguageClient
|
||||||
|
|||||||
@@ -31,10 +31,19 @@
|
|||||||
|
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
|
|
||||||
namespace TextEditor { class TextDocument; }
|
#include <functional>
|
||||||
|
|
||||||
|
namespace TextEditor {
|
||||||
|
class TextDocument;
|
||||||
|
class TextMark;
|
||||||
|
}
|
||||||
|
|
||||||
namespace LanguageClient {
|
namespace LanguageClient {
|
||||||
|
|
||||||
|
using TextMarkCreator = std::function<TextEditor::TextMark *(const Utils::FilePath &,
|
||||||
|
const LanguageServerProtocol::Diagnostic &)>;
|
||||||
|
using HideDiagnosticsHandler = std::function<void()>;
|
||||||
|
|
||||||
class DiagnosticManager
|
class DiagnosticManager
|
||||||
{
|
{
|
||||||
Q_DECLARE_TR_FUNCTIONS(LanguageClient::DiagnosticManager)
|
Q_DECLARE_TR_FUNCTIONS(LanguageClient::DiagnosticManager)
|
||||||
@@ -55,6 +64,12 @@ public:
|
|||||||
QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(
|
QList<LanguageServerProtocol::Diagnostic> diagnosticsAt(
|
||||||
const LanguageServerProtocol::DocumentUri &uri,
|
const LanguageServerProtocol::DocumentUri &uri,
|
||||||
const QTextCursor &cursor) const;
|
const QTextCursor &cursor) const;
|
||||||
|
bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri,
|
||||||
|
const TextEditor::TextDocument *doc,
|
||||||
|
const LanguageServerProtocol::Diagnostic &diag) const;
|
||||||
|
|
||||||
|
void setDiagnosticsHandlers(const TextMarkCreator &shownHandler,
|
||||||
|
const HideDiagnosticsHandler &removalHandler);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct VersionedDiagnostics {
|
struct VersionedDiagnostics {
|
||||||
@@ -63,6 +78,8 @@ private:
|
|||||||
};
|
};
|
||||||
QMap<LanguageServerProtocol::DocumentUri, VersionedDiagnostics> m_diagnostics;
|
QMap<LanguageServerProtocol::DocumentUri, VersionedDiagnostics> m_diagnostics;
|
||||||
Utils::Id m_clientId;
|
Utils::Id m_clientId;
|
||||||
|
TextMarkCreator m_textMarkCreator;
|
||||||
|
HideDiagnosticsHandler m_hideHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace LanguageClient
|
} // namespace LanguageClient
|
||||||
|
|||||||
Reference in New Issue
Block a user