forked from qt-creator/qt-creator
QmlJS: Allow disabling static analyzer messages
Provide settings to define a customized set of enabled static analyzer messages. Fixes: QTCREATORBUG-29095 Change-Id: Id629e383dd9e3beeef98026759ac66716dc43d23 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
This commit is contained in:
@@ -7,11 +7,15 @@
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <qmljs/qmljscheck.h>
|
||||
#include <qmljs/qmljsstaticanalysismessage.h>
|
||||
#include <qmljstools/qmljstoolsconstants.h>
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/macroexpander.h>
|
||||
#include <utils/qtcsettings.h>
|
||||
#include <utils/treemodel.h>
|
||||
#include <utils/variablechooser.h>
|
||||
#include <qmljstools/qmljstoolsconstants.h>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
@@ -19,6 +23,7 @@
|
||||
#include <QLineEdit>
|
||||
#include <QSettings>
|
||||
#include <QTextStream>
|
||||
#include <QTreeView>
|
||||
|
||||
const char AUTO_FORMAT_ON_SAVE[] = "QmlJSEditor.AutoFormatOnSave";
|
||||
const char AUTO_FORMAT_ONLY_CURRENT_PROJECT[] = "QmlJSEditor.AutoFormatOnlyCurrentProject";
|
||||
@@ -31,6 +36,9 @@ const char UIQML_OPEN_MODE[] = "QmlJSEditor.openUiQmlMode";
|
||||
const char FORMAT_COMMAND[] = "QmlJSEditor.formatCommand";
|
||||
const char FORMAT_COMMAND_OPTIONS[] = "QmlJSEditor.formatCommandOptions";
|
||||
const char CUSTOM_COMMAND[] = "QmlJSEditor.useCustomFormatCommand";
|
||||
const char CUSTOM_ANALYZER[] = "QmlJSEditor.useCustomAnalyzer";
|
||||
const char DISABLED_MESSAGES[] = "QmlJSEditor.disabledMessages";
|
||||
const char DISABLED_MESSAGES_NONQUICKUI[] = "QmlJSEditor.disabledMessagesNonQuickUI";
|
||||
const char DEFAULT_CUSTOM_FORMAT_COMMAND[] = "%{CurrentDocument:Project:QT_HOST_BINS}/qmlformat";
|
||||
|
||||
using namespace QmlJSEditor;
|
||||
@@ -57,6 +65,23 @@ void QmlJsEditingSettings::fromSettings(QSettings *settings)
|
||||
m_formatCommand = settings->value(FORMAT_COMMAND, {}).toString();
|
||||
m_formatCommandOptions = settings->value(FORMAT_COMMAND_OPTIONS, {}).toString();
|
||||
m_useCustomFormatCommand = settings->value(CUSTOM_COMMAND, QVariant(false)).toBool();
|
||||
m_useCustomAnalyzer = settings->value(CUSTOM_ANALYZER, QVariant(false)).toBool();
|
||||
|
||||
const QList<int> disabledByDefault = Utils::transform(
|
||||
QmlJS::Check::defaultDisabledMessages(),
|
||||
[](QmlJS::StaticAnalysis::Type t) { return int(t); });
|
||||
m_disabledMessages = Utils::transform<QSet>(
|
||||
settings->value(DISABLED_MESSAGES,
|
||||
QVariant::fromValue(disabledByDefault)).toList(),
|
||||
[](const QVariant &v){ return v.toInt(); });
|
||||
const QList<int> disabledForNonQuickUi = Utils::transform(
|
||||
QmlJS::Check::defaultDisabledMessagesForNonQuickUi(),
|
||||
[](QmlJS::StaticAnalysis::Type t){ return int(t); });
|
||||
m_disabledMessagesForNonQuickUi = Utils::transform<QSet>(
|
||||
settings->value(DISABLED_MESSAGES_NONQUICKUI,
|
||||
QVariant::fromValue(disabledForNonQuickUi)).toList(),
|
||||
[](const QVariant &v) { return v.toInt(); });
|
||||
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
@@ -80,6 +105,24 @@ void QmlJsEditingSettings::toSettings(QSettings *settings) const
|
||||
CUSTOM_COMMAND,
|
||||
m_useCustomFormatCommand,
|
||||
false);
|
||||
Utils::QtcSettings::setValueWithDefault(settings,
|
||||
CUSTOM_ANALYZER,
|
||||
m_useCustomAnalyzer,
|
||||
false);
|
||||
const QList<int> disabledByDefault = Utils::transform(
|
||||
QmlJS::Check::defaultDisabledMessages(),
|
||||
[](QmlJS::StaticAnalysis::Type t){ return int(t); });
|
||||
Utils::QtcSettings::setValueWithDefault(settings,
|
||||
DISABLED_MESSAGES,
|
||||
Utils::sorted(Utils::toList(m_disabledMessages)),
|
||||
disabledByDefault);
|
||||
const QList<int> disabledNonQuickUi = Utils::transform(
|
||||
QmlJS::Check::defaultDisabledMessagesForNonQuickUi(),
|
||||
[](QmlJS::StaticAnalysis::Type t){ return int(t); });
|
||||
Utils::QtcSettings::setValueWithDefault(settings,
|
||||
DISABLED_MESSAGES_NONQUICKUI,
|
||||
Utils::sorted(Utils::toList(m_disabledMessagesForNonQuickUi)),
|
||||
disabledNonQuickUi);
|
||||
settings->endGroup();
|
||||
QmllsSettingsManager::instance()->checkForChanges();
|
||||
}
|
||||
@@ -93,7 +136,10 @@ bool QmlJsEditingSettings::equals(const QmlJsEditingSettings &other) const
|
||||
&& m_foldAuxData == other.m_foldAuxData && m_qmllsSettings == other.m_qmllsSettings
|
||||
&& m_uiQmlOpenMode == other.m_uiQmlOpenMode && m_formatCommand == other.m_formatCommand
|
||||
&& m_formatCommandOptions == other.m_formatCommandOptions
|
||||
&& m_useCustomFormatCommand == other.m_useCustomFormatCommand;
|
||||
&& m_useCustomFormatCommand == other.m_useCustomFormatCommand
|
||||
&& m_useCustomAnalyzer == other.m_useCustomAnalyzer
|
||||
&& m_disabledMessages == other.m_disabledMessages
|
||||
&& m_disabledMessagesForNonQuickUi == other.m_disabledMessagesForNonQuickUi;
|
||||
}
|
||||
|
||||
bool QmlJsEditingSettings::enableContextPane() const
|
||||
@@ -201,6 +247,92 @@ void QmlJsEditingSettings::setUiQmlOpenMode(const QString &mode)
|
||||
m_uiQmlOpenMode = mode;
|
||||
}
|
||||
|
||||
bool QmlJsEditingSettings::useCustomAnalyzer() const
|
||||
{
|
||||
return m_useCustomAnalyzer;
|
||||
}
|
||||
|
||||
void QmlJsEditingSettings::setUseCustomAnalyzer(bool customAnalyzer)
|
||||
{
|
||||
m_useCustomAnalyzer = customAnalyzer;
|
||||
}
|
||||
|
||||
QSet<int> QmlJsEditingSettings::disabledMessages() const
|
||||
{
|
||||
return m_disabledMessages;
|
||||
}
|
||||
|
||||
void QmlJsEditingSettings::setDisabledMessages(const QSet<int> &disabled)
|
||||
{
|
||||
m_disabledMessages = disabled;
|
||||
}
|
||||
|
||||
QSet<int> QmlJsEditingSettings::disabledMessagesForNonQuickUi() const
|
||||
{
|
||||
return m_disabledMessagesForNonQuickUi;
|
||||
}
|
||||
|
||||
void QmlJsEditingSettings::setDisabledMessagesForNonQuickUi(const QSet<int> &disabled)
|
||||
{
|
||||
m_disabledMessagesForNonQuickUi = disabled;
|
||||
}
|
||||
|
||||
class AnalyzerMessageItem final : public Utils::TreeItem
|
||||
{
|
||||
public:
|
||||
AnalyzerMessageItem() = default;
|
||||
AnalyzerMessageItem(int number, const QString &message)
|
||||
: m_messageNumber(number)
|
||||
, m_message(message)
|
||||
{}
|
||||
|
||||
QVariant data(int column, int role) const final
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (column == 0)
|
||||
return QString("M%1").arg(m_messageNumber);
|
||||
if (column == 2)
|
||||
return m_message.split('\n').first();
|
||||
} else if (role == Qt::CheckStateRole) {
|
||||
if (column == 0)
|
||||
return m_checked ? Qt::Checked : Qt::Unchecked;
|
||||
if (column == 1)
|
||||
return m_disabledInNonQuickUi ? Qt::Checked : Qt::Unchecked;
|
||||
}
|
||||
return TreeItem::data(column, role);
|
||||
}
|
||||
|
||||
bool setData(int column, const QVariant &value, int role) final
|
||||
{
|
||||
if (role == Qt::CheckStateRole) {
|
||||
if (column == 0) {
|
||||
m_checked = value.toBool();
|
||||
return true;
|
||||
}
|
||||
if (column == 1) {
|
||||
m_disabledInNonQuickUi = value.toBool();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Qt::ItemFlags flags(int column) const final
|
||||
{
|
||||
if (column == 0 || column == 1)
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable;
|
||||
else
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
int messageNumber() const { return m_messageNumber; }
|
||||
private:
|
||||
int m_messageNumber = -1;
|
||||
QString m_message;
|
||||
bool m_checked = true;
|
||||
bool m_disabledInNonQuickUi = false;
|
||||
};
|
||||
|
||||
class QmlJsEditingSettingsPageWidget final : public Core::IOptionsPageWidget
|
||||
{
|
||||
public:
|
||||
@@ -247,6 +379,22 @@ public:
|
||||
useLatestQmlls->setEnabled(checked != Qt::Unchecked);
|
||||
});
|
||||
|
||||
useCustomAnalyzer = new QCheckBox(Tr::tr("Use customized static analyzer"));
|
||||
useCustomAnalyzer->setChecked(s.useCustomAnalyzer());
|
||||
analyzerMessageModel = new Utils::TreeModel<AnalyzerMessageItem>(this);
|
||||
analyzerMessageModel->setHeader({Tr::tr("Enabled"),
|
||||
Tr::tr("Disabled for non Qt Quick UI"),
|
||||
Tr::tr("Message")});
|
||||
analyzerMessagesView = new QTreeView;
|
||||
analyzerMessagesView->setModel(analyzerMessageModel);
|
||||
analyzerMessagesView->setEnabled(s.useCustomAnalyzer());
|
||||
QObject::connect(useCustomAnalyzer, &QCheckBox::stateChanged, this, [this](int checked){
|
||||
analyzerMessagesView->setEnabled(checked != Qt::Unchecked);
|
||||
});
|
||||
analyzerMessagesView->setToolTip(Tr::tr("Enabled checks can be disabled for non Qt Quick UI"
|
||||
" files,\nbut disabled checks cannot get explicitly"
|
||||
" enabled for non Qt Quick UI files."));
|
||||
|
||||
using namespace Layouting;
|
||||
// clang-format off
|
||||
QWidget *formattingGroup = nullptr;
|
||||
@@ -279,6 +427,10 @@ public:
|
||||
title(Tr::tr("Language Server")),
|
||||
Column{useQmlls, useLatestQmlls},
|
||||
},
|
||||
Group {
|
||||
title(Tr::tr("Static Analyzer")),
|
||||
Column{ useCustomAnalyzer, analyzerMessagesView },
|
||||
},
|
||||
st,
|
||||
}.attachTo(this);
|
||||
// clang-format on
|
||||
@@ -300,6 +452,8 @@ public:
|
||||
updateFormatCommandState();
|
||||
});
|
||||
connect(useCustomFormatCommand, &QCheckBox::toggled, this, updateFormatCommandState);
|
||||
|
||||
populateAnalyzerMessages(s.disabledMessages(), s.disabledMessagesForNonQuickUi());
|
||||
}
|
||||
|
||||
void apply() final
|
||||
@@ -316,10 +470,39 @@ public:
|
||||
s.setUiQmlOpenMode(uiQmlOpenComboBox->currentData().toString());
|
||||
s.qmllsSettings().useQmlls = useQmlls->isChecked();
|
||||
s.qmllsSettings().useLatestQmlls = useLatestQmlls->isChecked();
|
||||
s.setUseCustomAnalyzer(useCustomAnalyzer->isChecked());
|
||||
QSet<int> disabled;
|
||||
QSet<int> disabledForNonQuickUi;
|
||||
analyzerMessageModel->forAllItems(
|
||||
[&disabled, &disabledForNonQuickUi](AnalyzerMessageItem *item){
|
||||
if (item->data(0, Qt::CheckStateRole) == Qt::Unchecked)
|
||||
disabled.insert(item->messageNumber());
|
||||
if (item->data(1, Qt::CheckStateRole) == Qt::Checked)
|
||||
disabledForNonQuickUi.insert(item->messageNumber());
|
||||
});
|
||||
s.setDisabledMessages(disabled);
|
||||
s.setDisabledMessagesForNonQuickUi(disabledForNonQuickUi);
|
||||
s.set();
|
||||
}
|
||||
|
||||
private:
|
||||
void populateAnalyzerMessages(const QSet<int> &disabled, const QSet<int> &disabledForNonQuickUi)
|
||||
{
|
||||
using namespace QmlJS::StaticAnalysis;
|
||||
auto knownMessages = Utils::sorted(Message::allMessageTypes());
|
||||
auto root = analyzerMessageModel->rootItem();
|
||||
for (auto msgType : knownMessages) {
|
||||
const QString msg = Message::prototypeForMessageType(msgType).message;
|
||||
auto item = new AnalyzerMessageItem(msgType, msg);
|
||||
item->setData(0, !disabled.contains(msgType), Qt::CheckStateRole);
|
||||
item->setData(1, disabledForNonQuickUi.contains(msgType), Qt::CheckStateRole);
|
||||
root->appendChild(item);
|
||||
}
|
||||
|
||||
for (int column = 0; column < 3; ++column)
|
||||
analyzerMessagesView->resizeColumnToContents(column);
|
||||
}
|
||||
|
||||
QCheckBox *autoFormatOnSave;
|
||||
QCheckBox *autoFormatOnlyCurrentProject;
|
||||
QCheckBox *useCustomFormatCommand;
|
||||
@@ -331,6 +514,9 @@ private:
|
||||
QCheckBox *useQmlls;
|
||||
QCheckBox *useLatestQmlls;
|
||||
QComboBox *uiQmlOpenComboBox;
|
||||
QCheckBox *useCustomAnalyzer;
|
||||
QTreeView *analyzerMessagesView;
|
||||
Utils::TreeModel<AnalyzerMessageItem> *analyzerMessageModel;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -58,6 +58,15 @@ public:
|
||||
const QString uiQmlOpenMode() const;
|
||||
void setUiQmlOpenMode(const QString &mode);
|
||||
|
||||
bool useCustomAnalyzer() const;
|
||||
void setUseCustomAnalyzer(bool customAnalyzer);
|
||||
|
||||
QSet<int> disabledMessages() const;
|
||||
void setDisabledMessages(const QSet<int> &disabled);
|
||||
|
||||
QSet<int> disabledMessagesForNonQuickUi() const;
|
||||
void setDisabledMessagesForNonQuickUi(const QSet<int> &disabled);
|
||||
|
||||
friend bool operator==(const QmlJsEditingSettings &s1, const QmlJsEditingSettings &s2)
|
||||
{ return s1.equals(s2); }
|
||||
friend bool operator!=(const QmlJsEditingSettings &s1, const QmlJsEditingSettings &s2)
|
||||
@@ -70,10 +79,13 @@ private:
|
||||
bool m_autoFormatOnlyCurrentProject = false;
|
||||
bool m_foldAuxData = true;
|
||||
bool m_useCustomFormatCommand = false;
|
||||
bool m_useCustomAnalyzer = false;
|
||||
QmllsSettings m_qmllsSettings;
|
||||
QString m_uiQmlOpenMode;
|
||||
QString m_formatCommand;
|
||||
QString m_formatCommandOptions;
|
||||
QSet<int> m_disabledMessages;
|
||||
QSet<int> m_disabledMessagesForNonQuickUi;
|
||||
};
|
||||
|
||||
namespace Internal {
|
||||
|
||||
@@ -104,7 +104,7 @@ QmlJSTools::SemanticInfo SemanticInfoUpdater::makeNewSemanticInfo(const QmlJS::D
|
||||
semanticInfo.staticAnalysisMessages = jsonChecker(schema);
|
||||
}
|
||||
} else {
|
||||
Check checker(doc, semanticInfo.context);
|
||||
Check checker(doc, semanticInfo.context, Core::ICore::settings());
|
||||
semanticInfo.staticAnalysisMessages = checker();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "qmltaskmanager.h"
|
||||
#include "qmljseditorconstants.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/idocument.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/taskhub.h>
|
||||
@@ -87,7 +88,7 @@ void QmlTaskManager::collectMessages(QPromise<FileErrorMessages> &promise,
|
||||
fileName,
|
||||
Constants::TASK_CATEGORY_QML_ANALYSIS);
|
||||
|
||||
Check checker(document, context);
|
||||
Check checker(document, context, Core::ICore::settings());
|
||||
result.tasks += convertToTasks(checker(),
|
||||
fileName,
|
||||
Constants::TASK_CATEGORY_QML_ANALYSIS);
|
||||
|
||||
Reference in New Issue
Block a user