forked from qt-creator/qt-creator
Clang: Use CppHoverHandler for diagnostic tooltips
We used to call QTextCharFormat::setToolTip from the ExtraSelection to install the diagnostic tooltip. Since this allows to set only text tooltips and we would like to introduce a custom tooltip widget for diagnostics, make use of CppHoverHandler, which is more flexible. Change-Id: Ia1b2c3c50810596ce4a3a025002e6e4efd8789db Reviewed-by: Alessandro Portale <alessandro.portale@theqtcompany.com>
This commit is contained in:
committed by
Alessandro Portale
parent
593ed52c94
commit
9a4284d666
@@ -53,6 +53,7 @@ HEADERS += \
|
||||
clangfixitoperationsextractor.h \
|
||||
clangfunctionhintmodel.h \
|
||||
clanghighlightingmarksreporter.h \
|
||||
clangisdiagnosticrelatedtolocation.h \
|
||||
clangmodelmanagersupport.h \
|
||||
clangpreprocessorassistproposalitem.h \
|
||||
clangtextmark.h \
|
||||
|
||||
@@ -77,6 +77,7 @@ QtcPlugin {
|
||||
"clangfunctionhintmodel.h",
|
||||
"clanghighlightingmarksreporter.cpp",
|
||||
"clanghighlightingmarksreporter.h",
|
||||
"clangisdiagnosticrelatedtolocation.h",
|
||||
"clangmodelmanagersupport.cpp",
|
||||
"clangmodelmanagersupport.h",
|
||||
"clangpreprocessorassistproposalitem.cpp",
|
||||
|
||||
@@ -16,4 +16,5 @@ HEADERS += \
|
||||
$$PWD/clangcompletioncontextanalyzer.h \
|
||||
$$PWD/clangdiagnosticfilter.h \
|
||||
$$PWD/clangfixitoperation.h \
|
||||
$$PWD/clanghighlightingmarksreporter.h
|
||||
$$PWD/clanghighlightingmarksreporter.h \
|
||||
$$PWD/clangisdiagnosticrelatedtolocation.h
|
||||
|
||||
@@ -25,7 +25,9 @@
|
||||
|
||||
#include "clangdiagnosticfilter.h"
|
||||
#include "clangdiagnosticmanager.h"
|
||||
#include "clangisdiagnosticrelatedtolocation.h"
|
||||
|
||||
#include <texteditor/convenience.h>
|
||||
#include <texteditor/fontsettings.h>
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <texteditor/texteditorsettings.h>
|
||||
@@ -38,14 +40,12 @@
|
||||
namespace {
|
||||
|
||||
QTextEdit::ExtraSelection createExtraSelections(const QTextCharFormat &mainformat,
|
||||
const QTextCursor &cursor,
|
||||
const QString &diagnosticText)
|
||||
const QTextCursor &cursor)
|
||||
{
|
||||
QTextEdit::ExtraSelection extraSelection;
|
||||
|
||||
extraSelection.format = mainformat;
|
||||
extraSelection.cursor = cursor;
|
||||
extraSelection.format.setToolTip(diagnosticText);
|
||||
|
||||
return extraSelection;
|
||||
}
|
||||
@@ -61,7 +61,6 @@ int positionInText(QTextDocument *textDocument,
|
||||
void addRangeSelections(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||
QTextDocument *textDocument,
|
||||
const QTextCharFormat &contextFormat,
|
||||
const QString &diagnosticText,
|
||||
QList<QTextEdit::ExtraSelection> &extraSelections)
|
||||
{
|
||||
for (auto &&range : diagnostic.ranges()) {
|
||||
@@ -69,7 +68,7 @@ void addRangeSelections(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||
cursor.setPosition(positionInText(textDocument, range.start()));
|
||||
cursor.setPosition(positionInText(textDocument, range.end()), QTextCursor::KeepAnchor);
|
||||
|
||||
auto extraSelection = createExtraSelections(contextFormat, cursor, diagnosticText);
|
||||
auto extraSelection = createExtraSelections(contextFormat, cursor);
|
||||
|
||||
extraSelections.push_back(std::move(extraSelection));
|
||||
}
|
||||
@@ -90,37 +89,6 @@ QTextCursor createSelectionCursor(QTextDocument *textDocument,
|
||||
return cursor;
|
||||
}
|
||||
|
||||
bool isHelpfulChildDiagnostic(const ClangBackEnd::DiagnosticContainer &parentDiagnostic,
|
||||
const ClangBackEnd::DiagnosticContainer &childDiagnostic)
|
||||
{
|
||||
auto parentLocation = parentDiagnostic.location();
|
||||
auto childLocation = childDiagnostic.location();
|
||||
|
||||
return parentLocation == childLocation;
|
||||
}
|
||||
|
||||
QString diagnosticText(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||
{
|
||||
QString text = diagnostic.category().toString()
|
||||
+ QStringLiteral("\n\n")
|
||||
+ diagnostic.text().toString();
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
if (!diagnostic.disableOption().isEmpty()) {
|
||||
text += QStringLiteral(" (disable with ")
|
||||
+ diagnostic.disableOption().toString()
|
||||
+ QStringLiteral(")");
|
||||
}
|
||||
#endif
|
||||
|
||||
for (auto &&childDiagnostic : diagnostic.children()) {
|
||||
if (isHelpfulChildDiagnostic(diagnostic, childDiagnostic))
|
||||
text += QStringLiteral("\n ") + childDiagnostic.text().toString();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void addSelections(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||
QTextDocument *textDocument,
|
||||
const QTextCharFormat &mainFormat,
|
||||
@@ -129,11 +97,9 @@ void addSelections(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics
|
||||
{
|
||||
for (auto &&diagnostic : diagnostics) {
|
||||
auto cursor = createSelectionCursor(textDocument, diagnostic.location());
|
||||
auto extraSelection = createExtraSelections(mainFormat, cursor);
|
||||
|
||||
auto text = diagnosticText(diagnostic);
|
||||
auto extraSelection = createExtraSelections(mainFormat, cursor, text);
|
||||
|
||||
addRangeSelections(diagnostic, textDocument, contextFormat, text, extraSelections);
|
||||
addRangeSelections(diagnostic, textDocument, contextFormat, extraSelections);
|
||||
|
||||
extraSelections.push_back(std::move(extraSelection));
|
||||
}
|
||||
@@ -164,6 +130,69 @@ void addErrorSelections(const QVector<ClangBackEnd::DiagnosticContainer> &diagno
|
||||
addSelections(diagnostics, textDocument, errorFormat, errorContextFormat, extraSelections);
|
||||
}
|
||||
|
||||
ClangBackEnd::SourceLocationContainer toSourceLocation(QTextDocument *textDocument, int position)
|
||||
{
|
||||
int line, column;
|
||||
if (TextEditor::Convenience::convertPosition(textDocument, position, &line, &column))
|
||||
return ClangBackEnd::SourceLocationContainer(Utf8String(), line, column);
|
||||
|
||||
return ClangBackEnd::SourceLocationContainer();
|
||||
}
|
||||
|
||||
ClangBackEnd::SourceRangeContainer toSourceRange(const QTextCursor &cursor)
|
||||
{
|
||||
using namespace ClangBackEnd;
|
||||
|
||||
QTextDocument *textDocument = cursor.document();
|
||||
|
||||
return SourceRangeContainer(toSourceLocation(textDocument, cursor.anchor()),
|
||||
toSourceLocation(textDocument, cursor.position()));
|
||||
}
|
||||
|
||||
bool isDiagnosticAtLocation(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||
uint line,
|
||||
uint column,
|
||||
QTextDocument *textDocument)
|
||||
{
|
||||
using namespace ClangCodeModel::Internal;
|
||||
|
||||
const ClangBackEnd::SourceLocationContainer &location = diagnostic.location();
|
||||
const QTextCursor cursor = createSelectionCursor(textDocument, location);
|
||||
const ClangBackEnd::SourceRangeContainer cursorRange = toSourceRange(cursor);
|
||||
|
||||
return isDiagnosticRelatedToLocation(diagnostic, {cursorRange}, line, column);
|
||||
}
|
||||
|
||||
QVector<ClangBackEnd::DiagnosticContainer>
|
||||
filteredDiagnosticsAtLocation(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||
uint line,
|
||||
uint column,
|
||||
QTextDocument *textDocument)
|
||||
{
|
||||
QVector<ClangBackEnd::DiagnosticContainer> filteredDiagnostics;
|
||||
|
||||
foreach (const auto &diagnostic, diagnostics) {
|
||||
if (isDiagnosticAtLocation(diagnostic, line, column, textDocument))
|
||||
filteredDiagnostics.append(diagnostic);
|
||||
}
|
||||
|
||||
return filteredDiagnostics;
|
||||
}
|
||||
|
||||
bool editorDocumentProcessorHasDiagnosticAt(
|
||||
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
|
||||
uint line,
|
||||
uint column,
|
||||
QTextDocument *textDocument)
|
||||
{
|
||||
foreach (const auto &diagnostic, diagnostics) {
|
||||
if (isDiagnosticAtLocation(diagnostic, line, column, textDocument))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
|
||||
namespace ClangCodeModel {
|
||||
@@ -192,6 +221,26 @@ QList<QTextEdit::ExtraSelection> ClangDiagnosticManager::takeExtraSelections()
|
||||
return extraSelections;
|
||||
}
|
||||
|
||||
bool ClangDiagnosticManager::hasDiagnosticsAt(uint line, uint column) const
|
||||
{
|
||||
QTextDocument *textDocument = m_textDocument->document();
|
||||
|
||||
return editorDocumentProcessorHasDiagnosticAt(m_errorDiagnostics, line, column, textDocument)
|
||||
|| editorDocumentProcessorHasDiagnosticAt(m_warningDiagnostics, line, column, textDocument);
|
||||
}
|
||||
|
||||
QVector<ClangBackEnd::DiagnosticContainer>
|
||||
ClangDiagnosticManager::diagnosticsAt(uint line, uint column) const
|
||||
{
|
||||
QTextDocument *textDocument = m_textDocument->document();
|
||||
|
||||
QVector<ClangBackEnd::DiagnosticContainer> diagnostics;
|
||||
diagnostics += filteredDiagnosticsAtLocation(m_errorDiagnostics, line, column, textDocument);
|
||||
diagnostics += filteredDiagnosticsAtLocation(m_warningDiagnostics, line, column, textDocument);
|
||||
|
||||
return diagnostics;
|
||||
}
|
||||
|
||||
void ClangDiagnosticManager::clearDiagnosticsWithFixIts()
|
||||
{
|
||||
m_fixItdiagnostics.clear();
|
||||
@@ -213,8 +262,6 @@ void ClangDiagnosticManager::processNewDiagnostics(
|
||||
|
||||
generateTextMarks();
|
||||
generateEditorSelections();
|
||||
|
||||
clearWarningsAndErrors();
|
||||
}
|
||||
|
||||
const QVector<ClangBackEnd::DiagnosticContainer> &
|
||||
@@ -241,12 +288,6 @@ void ClangDiagnosticManager::addClangTextMarks(
|
||||
}
|
||||
}
|
||||
|
||||
void ClangDiagnosticManager::clearWarningsAndErrors()
|
||||
{
|
||||
m_warningDiagnostics.clear();
|
||||
m_errorDiagnostics.clear();
|
||||
}
|
||||
|
||||
QString ClangDiagnosticManager::filePath() const
|
||||
{
|
||||
return m_textDocument->filePath().toString();
|
||||
|
||||
@@ -51,6 +51,9 @@ public:
|
||||
const QVector<ClangBackEnd::DiagnosticContainer> &diagnosticsWithFixIts() const;
|
||||
QList<QTextEdit::ExtraSelection> takeExtraSelections();
|
||||
|
||||
bool hasDiagnosticsAt(uint line, uint column) const;
|
||||
QVector<ClangBackEnd::DiagnosticContainer> diagnosticsAt(uint line, uint column) const;
|
||||
|
||||
void clearDiagnosticsWithFixIts();
|
||||
|
||||
private:
|
||||
@@ -59,7 +62,6 @@ private:
|
||||
void generateEditorSelections();
|
||||
void generateTextMarks();
|
||||
void addClangTextMarks(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics);
|
||||
void clearWarningsAndErrors();
|
||||
|
||||
private:
|
||||
TextEditor::TextDocument *m_textDocument;
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <cplusplus/CppDocument.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/tooltip/tooltip.h>
|
||||
#include <utils/QtConcurrentTools>
|
||||
|
||||
#include <QTextBlock>
|
||||
@@ -233,6 +234,73 @@ TextEditor::QuickFixOperations ClangEditorDocumentProcessor::extraRefactoringOpe
|
||||
return extractor.extract(assistInterface.fileName(), currentLine(assistInterface));
|
||||
}
|
||||
|
||||
bool ClangEditorDocumentProcessor::hasDiagnosticsAt(uint line, uint column) const
|
||||
{
|
||||
return m_diagnosticManager.hasDiagnosticsAt(line, column);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool isHelpfulChildDiagnostic(const ClangBackEnd::DiagnosticContainer &parentDiagnostic,
|
||||
const ClangBackEnd::DiagnosticContainer &childDiagnostic)
|
||||
{
|
||||
auto parentLocation = parentDiagnostic.location();
|
||||
auto childLocation = childDiagnostic.location();
|
||||
|
||||
return parentLocation == childLocation;
|
||||
}
|
||||
|
||||
QString diagnosticText(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
||||
{
|
||||
QString text = diagnostic.category().toString()
|
||||
+ QStringLiteral("\n\n")
|
||||
+ diagnostic.text().toString();
|
||||
|
||||
#ifdef QT_DEBUG
|
||||
if (!diagnostic.disableOption().isEmpty()) {
|
||||
text += QStringLiteral(" (disable with ")
|
||||
+ diagnostic.disableOption().toString()
|
||||
+ QStringLiteral(")");
|
||||
}
|
||||
#endif
|
||||
|
||||
for (auto &&childDiagnostic : diagnostic.children()) {
|
||||
if (isHelpfulChildDiagnostic(diagnostic, childDiagnostic))
|
||||
text += QStringLiteral("\n ") + childDiagnostic.text().toString();
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
QString generateTooltipText(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics)
|
||||
{
|
||||
QString text;
|
||||
|
||||
foreach (const ClangBackEnd::DiagnosticContainer &diagnostic, diagnostics) {
|
||||
if (text.isEmpty())
|
||||
text += diagnosticText(diagnostic);
|
||||
else
|
||||
text += QStringLiteral("\n\n\n") + diagnosticText(diagnostic);
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void ClangEditorDocumentProcessor::showDiagnosticTooltip(const QPoint &point,
|
||||
QWidget *parent,
|
||||
uint line,
|
||||
uint column) const
|
||||
{
|
||||
const QVector<ClangBackEnd::DiagnosticContainer> diagnostics
|
||||
= m_diagnosticManager.diagnosticsAt(line, column);
|
||||
|
||||
const QString tooltipText = generateTooltipText(diagnostics);
|
||||
|
||||
::Utils::ToolTip::show(point, tooltipText, parent);
|
||||
}
|
||||
|
||||
ClangBackEnd::FileContainer ClangEditorDocumentProcessor::fileContainerWithArguments() const
|
||||
{
|
||||
return fileContainerWithArguments(m_projectPart.data());
|
||||
|
||||
@@ -76,6 +76,12 @@ public:
|
||||
TextEditor::QuickFixOperations
|
||||
extraRefactoringOperations(const TextEditor::AssistInterface &assistInterface) override;
|
||||
|
||||
bool hasDiagnosticsAt(uint line, uint column) const override;
|
||||
void showDiagnosticTooltip(const QPoint &point,
|
||||
QWidget *parent,
|
||||
uint line,
|
||||
uint column) const override;
|
||||
|
||||
ClangBackEnd::FileContainer fileContainerWithArguments() const;
|
||||
|
||||
void clearDiagnosticsWithFixIts();
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 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 <clangbackendipc/diagnosticcontainer.h>
|
||||
|
||||
namespace ClangCodeModel {
|
||||
namespace Internal {
|
||||
|
||||
bool isWithinRange(const ClangBackEnd::SourceRangeContainer &range,
|
||||
uint line,
|
||||
uint column)
|
||||
{
|
||||
const ClangBackEnd::SourceLocationContainer startLocation = range.start();
|
||||
const ClangBackEnd::SourceLocationContainer endLocation = range.end();
|
||||
|
||||
return startLocation.line() <= line
|
||||
&& startLocation.column() <= column
|
||||
&& line <= endLocation.line()
|
||||
&& column <= endLocation.column();
|
||||
}
|
||||
|
||||
bool isWithinOneRange(const QVector<ClangBackEnd::SourceRangeContainer> &ranges,
|
||||
uint line,
|
||||
uint column)
|
||||
{
|
||||
foreach (const ClangBackEnd::SourceRangeContainer &range, ranges) {
|
||||
if (isWithinRange(range, line, column))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isDiagnosticRelatedToLocation(const ClangBackEnd::DiagnosticContainer &diagnostic,
|
||||
const QVector<ClangBackEnd::SourceRangeContainer> &additionalRanges,
|
||||
uint line,
|
||||
uint column)
|
||||
{
|
||||
const ClangBackEnd::SourceLocationContainer location = diagnostic.location();
|
||||
|
||||
if (location.line() == line && location.column() == column)
|
||||
return true;
|
||||
|
||||
if (isWithinOneRange(additionalRanges, line, column))
|
||||
return true;
|
||||
|
||||
if (isWithinOneRange(diagnostic.ranges(), line, column))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace ClangCodeModel
|
||||
Reference in New Issue
Block a user