Commit 89199b51 authored by Nikolai Kosjar's avatar Nikolai Kosjar

Clang: Indicate available "fix its" with a light bulb

...at the end of the line, just like for the "Apply Function Signature
Changes" refactor action.

* Hovering the light bulb shows the tooltip "Inspect available fixits".
* Clicking the light bulb leads to the refactoring menu, as if the user
  hit Alt+Return.

Change-Id: Iaf7b3734c43e21fc28e6b0658f517d98858c0e0c
Reviewed-by: default avatarAlessandro Portale <alessandro.portale@theqtcompany.com>
parent cd94f66a
......@@ -27,12 +27,18 @@
#include "clangdiagnosticmanager.h"
#include "clangisdiagnosticrelatedtolocation.h"
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
#include <cpptools/cpptoolsconstants.h>
#include <texteditor/convenience.h>
#include <texteditor/fontsettings.h>
#include <texteditor/textdocument.h>
#include <texteditor/texteditorsettings.h>
#include <utils/fileutils.h>
#include <utils/proxyaction.h>
#include <utils/qtcassert.h>
#include <QTextBlock>
......@@ -193,6 +199,40 @@ bool editorDocumentProcessorHasDiagnosticAt(
return false;
}
QTextCursor cursorAtLastPositionOfLine(QTextDocument *textDocument, int lineNumber)
{
const QTextBlock textBlock = textDocument->findBlockByNumber(lineNumber - 1);
QTC_ASSERT(textBlock.isValid(), return QTextCursor());
const int lastPositionOfLine = textBlock.position() + textBlock.length() - 1;
QTextCursor textCursor(textDocument);
textCursor.setPosition(lastPositionOfLine);
return textCursor;
}
QString tooltipForFixItAvailableMarker()
{
QString text = QObject::tr("Inspect available fixits");
Core::Command *command = Core::ActionManager::command(TextEditor::Constants::QUICKFIX_THIS);
if (command)
text = Utils::ProxyAction::stringWithAppendedShortcut(text, command->keySequence());
return text;
}
TextEditor::RefactorMarker createFixItAvailableMarker(QTextDocument *textDocument, int lineNumber)
{
TextEditor::RefactorMarker marker;
marker.tooltip = tooltipForFixItAvailableMarker();
marker.cursor = cursorAtLastPositionOfLine(textDocument, lineNumber);
marker.data = QLatin1String(CppTools::Constants::CPP_CLANG_FIXIT_AVAILABLE_MARKER_ID);
return marker;
}
} // anonymous
namespace ClangCodeModel {
......@@ -212,6 +252,15 @@ void ClangDiagnosticManager::generateTextMarks()
addClangTextMarks(m_errorDiagnostics);
}
void ClangDiagnosticManager::generateFixItAvailableMarkers()
{
m_fixItAvailableMarkers.clear();
QSet<int> lineNumbersWithFixItMarker;
addFixItAvailableMarker(m_warningDiagnostics, lineNumbersWithFixItMarker);
addFixItAvailableMarker(m_errorDiagnostics, lineNumbersWithFixItMarker);
}
QList<QTextEdit::ExtraSelection> ClangDiagnosticManager::takeExtraSelections()
{
auto extraSelections = m_extraSelections;
......@@ -221,6 +270,15 @@ QList<QTextEdit::ExtraSelection> ClangDiagnosticManager::takeExtraSelections()
return extraSelections;
}
TextEditor::RefactorMarkers ClangDiagnosticManager::takeFixItAvailableMarkers()
{
TextEditor::RefactorMarkers fixItAvailableMarkers = m_fixItAvailableMarkers;
m_fixItAvailableMarkers.clear();
return fixItAvailableMarkers;
}
bool ClangDiagnosticManager::hasDiagnosticsAt(uint line, uint column) const
{
QTextDocument *textDocument = m_textDocument->document();
......@@ -262,6 +320,7 @@ void ClangDiagnosticManager::processNewDiagnostics(
generateTextMarks();
generateEditorSelections();
generateFixItAvailableMarkers();
}
const QVector<ClangBackEnd::DiagnosticContainer> &
......@@ -288,6 +347,24 @@ void ClangDiagnosticManager::addClangTextMarks(
}
}
void ClangDiagnosticManager::addFixItAvailableMarker(
const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
QSet<int> &lineNumbersWithFixItMarker)
{
for (auto &&diagnostic : diagnostics) {
const int line = int(diagnostic.location().line());
if (!diagnostic.fixIts().isEmpty() && !lineNumbersWithFixItMarker.contains(line)) {
const TextEditor::RefactorMarker marker
= createFixItAvailableMarker(m_textDocument->document(), line);
lineNumbersWithFixItMarker.insert(line);
m_fixItAvailableMarkers.append(marker);
}
addFixItAvailableMarker(diagnostic.children(), lineNumbersWithFixItMarker);
}
}
QString ClangDiagnosticManager::filePath() const
{
return m_textDocument->filePath().toString();
......
......@@ -28,9 +28,12 @@
#include "clangtextmark.h"
#include <texteditor/refactoroverlay.h>
#include <clangbackendipc/diagnosticcontainer.h>
#include <QList>
#include <QSet>
#include <QTextEdit>
#include <QVector>
......@@ -50,6 +53,7 @@ public:
const QVector<ClangBackEnd::DiagnosticContainer> &diagnosticsWithFixIts() const;
QList<QTextEdit::ExtraSelection> takeExtraSelections();
TextEditor::RefactorMarkers takeFixItAvailableMarkers();
bool hasDiagnosticsAt(uint line, uint column) const;
QVector<ClangBackEnd::DiagnosticContainer> diagnosticsAt(uint line, uint column) const;
......@@ -61,7 +65,10 @@ private:
void filterDiagnostics(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics);
void generateEditorSelections();
void generateTextMarks();
void generateFixItAvailableMarkers();
void addClangTextMarks(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics);
void addFixItAvailableMarker(const QVector<ClangBackEnd::DiagnosticContainer> &diagnostics,
QSet<int> &lineNumbersWithFixItMarker);
private:
TextEditor::TextDocument *m_textDocument;
......@@ -70,6 +77,7 @@ private:
QVector<ClangBackEnd::DiagnosticContainer> m_errorDiagnostics;
QVector<ClangBackEnd::DiagnosticContainer> m_fixItdiagnostics;
QList<QTextEdit::ExtraSelection> m_extraSelections;
TextEditor::RefactorMarkers m_fixItAvailableMarkers;
std::vector<ClangTextMark> m_clangTextMarks;
};
......
......@@ -164,7 +164,8 @@ void ClangEditorDocumentProcessor::updateCodeWarnings(const QVector<ClangBackEnd
if (documentRevision == revision()) {
m_diagnosticManager.processNewDiagnostics(diagnostics);
const auto codeWarnings = m_diagnosticManager.takeExtraSelections();
emit codeWarningsUpdated(revision(), codeWarnings);
const auto fixitAvailableMarkers = m_diagnosticManager.takeFixItAvailableMarkers();
emit codeWarningsUpdated(revision(), codeWarnings, fixitAvailableMarkers);
}
}
namespace {
......
......@@ -56,6 +56,7 @@
#include <cpptools/symbolfinder.h>
#include <texteditor/completionsettings.h>
#include <texteditor/convenience.h>
#include <texteditor/textdocument.h>
#include <texteditor/textdocumentlayout.h>
#include <texteditor/texteditorsettings.h>
......@@ -271,11 +272,14 @@ void CppEditorWidget::onCppDocumentUpdated()
}
void CppEditorWidget::onCodeWarningsUpdated(unsigned revision,
const QList<QTextEdit::ExtraSelection> selections)
const QList<QTextEdit::ExtraSelection> selections,
const TextEditor::RefactorMarkers &refactorMarkers)
{
if (revision != documentRevision())
return;
setExtraSelections(TextEditorWidget::CodeWarningsSelection, selections);
setRefactorMarkers(refactorMarkersWithoutClangMarkers() + refactorMarkers);
}
void CppEditorWidget::onIfdefedOutBlocksUpdated(unsigned revision,
......@@ -428,6 +432,26 @@ unsigned CppEditorWidget::documentRevision() const
return document()->revision();
}
static bool isClangFixItAvailableMarker(const RefactorMarker &marker)
{
return marker.data.toString()
== QLatin1String(CppTools::Constants::CPP_CLANG_FIXIT_AVAILABLE_MARKER_ID);
}
RefactorMarkers CppEditorWidget::refactorMarkersWithoutClangMarkers() const
{
RefactorMarkers clearedRefactorMarkers;
foreach (const RefactorMarker &marker, refactorMarkers()) {
if (isClangFixItAvailableMarker(marker))
continue;
clearedRefactorMarkers.append(marker);
}
return clearedRefactorMarkers;
}
bool CppEditorWidget::isSemanticInfoValidExceptLocalUses() const
{
return d->m_lastSemanticInfo.doc
......@@ -631,8 +655,15 @@ QSharedPointer<FunctionDeclDefLink> CppEditorWidget::declDefLink() const
void CppEditorWidget::onRefactorMarkerClicked(const RefactorMarker &marker)
{
if (marker.data.canConvert<FunctionDeclDefLink::Marker>())
if (marker.data.canConvert<FunctionDeclDefLink::Marker>()) {
applyDeclDefLinkChanges(true);
} else if (isClangFixItAvailableMarker(marker)) {
int line, column;
if (Convenience::convertPosition(document(), marker.cursor.position(), &line, &column)) {
setTextCursor(marker.cursor);
invokeAssist(TextEditor::QuickFix);
}
}
}
void CppEditorWidget::updateFunctionDeclDefLink()
......
......@@ -115,7 +115,8 @@ private slots:
void onCppDocumentUpdated();
void onCodeWarningsUpdated(unsigned revision,
const QList<QTextEdit::ExtraSelection> selections);
const QList<QTextEdit::ExtraSelection> selections,
const TextEditor::RefactorMarkers &refactorMarkers);
void onIfdefedOutBlocksUpdated(unsigned revision,
const QList<TextEditor::BlockRange> ifdefedOutBlocks);
......@@ -133,6 +134,8 @@ private:
unsigned documentRevision() const;
TextEditor::RefactorMarkers refactorMarkersWithoutClangMarkers() const;
private:
QScopedPointer<CppEditorWidgetPrivate> d;
};
......
......@@ -60,7 +60,8 @@ public:
signals:
void codeWarningsUpdated(unsigned contentsRevision,
const QList<QTextEdit::ExtraSelection> selections);
const QList<QTextEdit::ExtraSelection> selections,
const TextEditor::RefactorMarkers &refactorMarkers);
void ifdefedOutBlocksUpdated(unsigned contentsRevision,
const QList<TextEditor::BlockRange> ifdefedOutBlocks);
......
......@@ -74,7 +74,8 @@ public:
signals:
// Signal interface to implement
void codeWarningsUpdated(unsigned revision,
const QList<QTextEdit::ExtraSelection> selections);
const QList<QTextEdit::ExtraSelection> selections,
const TextEditor::RefactorMarkers &refactorMarkers);
void ifdefedOutBlocksUpdated(unsigned revision,
const QList<TextEditor::BlockRange> ifdefedOutBlocks);
......
......@@ -34,6 +34,7 @@
#include <texteditor/convenience.h>
#include <texteditor/fontsettings.h>
#include <texteditor/refactoroverlay.h>
#include <texteditor/texteditorsettings.h>
#include <cplusplus/CppDocument.h>
......@@ -307,7 +308,7 @@ void BuiltinEditorDocumentProcessor::onCodeWarningsUpdated(
m_codeWarnings += toTextEditorSelections(codeWarnings, textDocument());
m_codeWarningsUpdated = true;
emit codeWarningsUpdated(revision(), m_codeWarnings);
emit codeWarningsUpdated(revision(), m_codeWarnings, TextEditor::RefactorMarkers());
}
SemanticInfo::Source BuiltinEditorDocumentProcessor::createSemanticInfoSource(bool force) const
......
......@@ -61,6 +61,8 @@ const char CPP_SETTINGS_CATEGORY[] = "I.C++";
const char CPP_SETTINGS_TR_CATEGORY[] = QT_TRANSLATE_NOOP("CppTools", "C++");
const char SETTINGS_CATEGORY_CPP_ICON[] = ":/cpptools/images/category_cpp.png";
const char CPP_CLANG_FIXIT_AVAILABLE_MARKER_ID[] = "ClangFixItAvailableMarker";
const char CPP_SETTINGS_ID[] = "Cpp";
const char CPP_SETTINGS_NAME[] = QT_TRANSLATE_NOOP("CppTools", "C++");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment