QmlJSEditor: Display code model warnings as annotations

Change-Id: Ief6ed8fe551846f5e788c14a49269231462ea40a
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Reviewed-by: Marco Benelli <marco.benelli@qt.io>
This commit is contained in:
David Schulz
2017-11-15 15:01:54 +01:00
parent 5ef41157c7
commit b9d00c3f27
6 changed files with 234 additions and 2 deletions

View File

@@ -34,6 +34,7 @@
#include "qmljshighlighter.h"
#include "qmljshoverhandler.h"
#include "qmljsquickfixassist.h"
#include "qmljstextmark.h"
#include "qmloutlinemodel.h"
#include <qmljs/qmljsbind.h>
@@ -68,6 +69,7 @@
#include <texteditor/codeassist/genericproposal.h>
#include <texteditor/codeassist/genericproposalmodel.h>
#include <texteditor/texteditoractionhandler.h>
#include <texteditor/textmark.h>
#include <utils/annotateditemdelegate.h>
#include <utils/changeset.h>
@@ -201,12 +203,14 @@ static void appendExtraSelectionsForMessages(
void QmlJSEditorWidget::updateCodeWarnings(Document::Ptr doc)
{
cleanDiagnosticMarks();
if (doc->ast()) {
setExtraSelections(CodeWarningsSelection, QList<QTextEdit::ExtraSelection>());
} else if (doc->language().isFullySupportedLanguage()) {
// show parsing errors
QList<QTextEdit::ExtraSelection> selections;
appendExtraSelectionsForMessages(&selections, doc->diagnosticMessages(), document());
createTextMarks(doc->diagnosticMessages());
setExtraSelections(CodeWarningsSelection, selections);
} else {
setExtraSelections(CodeWarningsSelection, QList<QTextEdit::ExtraSelection>());
@@ -923,6 +927,8 @@ void QmlJSEditorWidget::semanticInfoUpdated(const SemanticInfo &semanticInfo)
}
}
createTextMarks(semanticInfo);
updateUses();
}
@@ -964,6 +970,61 @@ bool QmlJSEditorWidget::hideContextPane()
return b;
}
void QmlJSEditorWidget::createTextMarks(const QList<DiagnosticMessage> &diagnostics)
{
for (const DiagnosticMessage &diagnostic : diagnostics) {
const auto onMarkRemoved = [this](QmlJSTextMark *mark) {
m_diagnosticMarks.removeAll(mark);
delete mark;
};
auto mark = new QmlJSTextMark(textDocument()->filePath().toString(),
diagnostic, onMarkRemoved);
m_diagnosticMarks.append(mark);
textDocument()->addMark(mark);
}
}
static void cleanMarks(QVector<TextMark *> *marks, TextDocument *doc)
{
for (TextEditor::TextMark *mark : *marks) {
doc->removeMark(mark);
delete mark;
}
marks->clear();
}
void QmlJSEditorWidget::cleanDiagnosticMarks()
{
cleanMarks(&m_diagnosticMarks, textDocument());
}
void QmlJSEditorWidget::createTextMarks(const SemanticInfo &info)
{
cleanSemanticMarks();
const auto onMarkRemoved = [this](QmlJSTextMark *mark) {
m_semanticMarks.removeAll(mark);
delete mark;
};
for (const DiagnosticMessage &diagnostic : info.semanticMessages) {
auto mark = new QmlJSTextMark(textDocument()->filePath().toString(),
diagnostic, onMarkRemoved);
m_semanticMarks.append(mark);
textDocument()->addMark(mark);
}
for (const QmlJS::StaticAnalysis::Message &message : info.staticAnalysisMessages) {
auto mark = new QmlJSTextMark(textDocument()->filePath().toString(),
message, onMarkRemoved);
m_semanticMarks.append(mark);
textDocument()->addMark(mark);
}
}
void QmlJSEditorWidget::cleanSemanticMarks()
{
cleanMarks(&m_semanticMarks, textDocument());
}
AssistInterface *QmlJSEditorWidget::createAssistInterface(
AssistKind assistKind,
AssistReason reason) const

View File

@@ -47,6 +47,8 @@ namespace QmlJS {
namespace AST { class UiObjectMember; }
}
namespace TextEditor { class TextMark; }
namespace QmlJSEditor {
class QmlJSEditorDocument;
@@ -127,6 +129,14 @@ private:
QmlJS::IContextPane *m_contextPane = nullptr;
int m_oldCursorPosition = -1;
void createTextMarks(const QList<QmlJS::DiagnosticMessage> &diagnostics);
void cleanDiagnosticMarks();
QVector<TextEditor::TextMark *> m_diagnosticMarks;
void createTextMarks(const QmlJSTools::SemanticInfo &info);
void cleanSemanticMarks();
QVector<TextEditor::TextMark *> m_semanticMarks;
FindReferences *m_findReferences;
};

View File

@@ -30,7 +30,8 @@ HEADERS += \
qmljssemantichighlighter.h \
qmljswrapinloader.h \
qmljseditordocument.h \
qmljseditordocument_p.h
qmljseditordocument_p.h \
qmljstextmark.h
SOURCES += \
qmljseditor.cpp \
@@ -57,7 +58,8 @@ SOURCES += \
qmljssemanticinfoupdater.cpp \
qmljssemantichighlighter.cpp \
qmljswrapinloader.cpp \
qmljseditordocument.cpp
qmljseditordocument.cpp \
qmljstextmark.cpp
FORMS += \
qmljseditingsettingspage.ui \

View File

@@ -61,6 +61,8 @@ QtcPlugin {
"qmljssemantichighlighter.h",
"qmljssemanticinfoupdater.cpp",
"qmljssemanticinfoupdater.h",
"qmljstextmark.cpp",
"qmljstextmark.h",
"qmljswrapinloader.cpp",
"qmljswrapinloader.h",
"qmloutlinemodel.cpp",

View File

@@ -0,0 +1,100 @@
/****************************************************************************
**
** Copyright (C) 2017 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 "qmljstextmark.h"
#include <utils/qtcassert.h>
#include <utils/utilsicons.h>
#include <QApplication>
using namespace QmlJSEditor;
using namespace QmlJSEditor::Internal;
using namespace TextEditor;
const char QMLJS_ERROR[] = "QmlJS.Error";
const char QMLJS_WARNING[] = "QmlJS.Warning";
static bool isWarning(QmlJS::Severity::Enum kind)
{
switch (kind) {
case QmlJS::Severity::Hint:
case QmlJS::Severity::MaybeWarning:
case QmlJS::Severity::Warning:
case QmlJS::Severity::ReadingTypeInfoWarning:
return true;
case QmlJS::Severity::MaybeError:
case QmlJS::Severity::Error:
break;
}
return false;
}
static Core::Id cartegoryForSeverity(QmlJS::Severity::Enum kind)
{
return isWarning(kind) ? QMLJS_WARNING : QMLJS_ERROR;
}
QmlJSTextMark::QmlJSTextMark(const QString &fileName,
const QmlJS::DiagnosticMessage &diagnostic,
const QmlJSTextMark::RemovedFromEditorHandler &removedHandler)
: TextEditor::TextMark(fileName, int(diagnostic.loc.startLine),
cartegoryForSeverity(diagnostic.kind))
, m_removedFromEditorHandler(removedHandler)
{
init(isWarning(diagnostic.kind), diagnostic.message);
}
QmlJSTextMark::QmlJSTextMark(const QString &fileName,
const QmlJS::StaticAnalysis::Message &message,
const QmlJSTextMark::RemovedFromEditorHandler &removedHandler)
: TextEditor::TextMark(fileName, int(message.location.startLine),
cartegoryForSeverity(message.severity))
, m_removedFromEditorHandler(removedHandler)
{
init(isWarning(message.severity), message.message);
}
void QmlJSTextMark::removedFromEditor()
{
QTC_ASSERT(m_removedFromEditorHandler, return);
m_removedFromEditorHandler(this);
}
void QmlJSTextMark::init(bool warning, const QString message)
{
setIcon(warning ? Utils::Icons::CODEMODEL_WARNING.icon()
: Utils::Icons::CODEMODEL_ERROR.icon());
setColor(warning ? Utils::Theme::ClangCodeModel_Warning_TextMarkColor
: Utils::Theme::ClangCodeModel_Error_TextMarkColor);
setDefaultToolTip(warning ? QApplication::translate("QmlJS Code Model Marks", "Code Model Warning")
: QApplication::translate("QmlJS Code Model Marks", "Code Model Error"));
setToolTip(message);
setPriority(warning ? TextEditor::TextMark::NormalPriority
: TextEditor::TextMark::HighPriority);
setLineAnnotation(message);
}

View File

@@ -0,0 +1,57 @@
/****************************************************************************
**
** Copyright (C) 2017 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 <qmljs/qmljsdocument.h>
#include <qmljs/qmljsstaticanalysismessage.h>
#include <texteditor/textmark.h>
namespace QmlJSEditor {
namespace Internal {
class QmlJSTextMark : public TextEditor::TextMark
{
public:
using RemovedFromEditorHandler = std::function<void(QmlJSTextMark *)>;
QmlJSTextMark(const QString &fileName,
const QmlJS::DiagnosticMessage &diagnostic,
const RemovedFromEditorHandler &removedHandler);
QmlJSTextMark(const QString &fileName,
const QmlJS::StaticAnalysis::Message &message,
const RemovedFromEditorHandler &removedHandler);
private:
void removedFromEditor() override;
void init(bool warning, const QString message);
private:
RemovedFromEditorHandler m_removedFromEditorHandler;
};
} // namespace Internal
} // namespace QmlJSEditor