Clang: Add tooltip action to remove specific warnings/checks

...from the diagnostic configuration.

If no custom diagnostic configuration is set in Projects Mode > Clang,
one is created and set for the current project. Otherwise the current
custom diagnostic set in the project settings is modified.

Change-Id: I5c48280c90f0e807e7333122d504dda302a8b0a9
Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
This commit is contained in:
Nikolai Kosjar
2019-01-28 12:40:03 +01:00
parent b9d3055e72
commit f6c46ce35d
9 changed files with 226 additions and 79 deletions

View File

@@ -25,6 +25,7 @@
#include "clangdiagnostictooltipwidget.h"
#include "clangfixitoperation.h"
#include "clangutils.h"
#include <coreplugin/editormanager/editormanager.h>
@@ -149,7 +150,7 @@ public:
QTC_CHECK(!"Link target cannot be handled.");
if (hideToolTipAfterLinkActivation)
Utils::ToolTip::hideImmediately();
::Utils::ToolTip::hideImmediately();
});
return label;
@@ -171,50 +172,6 @@ public:
private:
enum class IndentMode { Indent, DoNotIndent };
static bool isClazyOption(const QString &option) { return option.startsWith("-Wclazy"); }
class DiagnosticTextInfo
{
public:
DiagnosticTextInfo(const QString &text)
: m_text(text)
, m_squareBracketStartIndex(text.lastIndexOf('['))
{}
QString textWithoutOption() const
{
if (m_squareBracketStartIndex == -1)
return m_text;
return m_text.mid(0, m_squareBracketStartIndex - 1);
}
QString option() const
{
if (m_squareBracketStartIndex == -1)
return QString();
const int index = m_squareBracketStartIndex + 1;
return m_text.mid(index, m_text.count() - index - 1);
}
QString category() const
{
if (m_squareBracketStartIndex == -1)
return QString();
const int index = m_squareBracketStartIndex + 1;
if (isClazyOption(m_text.mid(index)))
return QCoreApplication::translate("ClangDiagnosticWidget", "Clazy Issue");
else
return QCoreApplication::translate("ClangDiagnosticWidget", "Clang-Tidy Issue");
}
private:
const QString m_text;
const int m_squareBracketStartIndex;
};
// Diagnostics from clazy/tidy do not have any category or option set but
// we will conclude them from the diagnostic message.
//
@@ -233,6 +190,7 @@ private:
ClangBackEnd::DiagnosticContainer supplementedDiagnostic = diagnostic;
using namespace ClangCodeModel::Utils;
DiagnosticTextInfo info(diagnostic.text);
supplementedDiagnostic.enableOption = info.option();
supplementedDiagnostic.category = info.category();
@@ -269,7 +227,7 @@ private:
QString option = optionAsUtf8String.toString();
// Clazy
if (isClazyOption(option)) {
if (ClangCodeModel::Utils::DiagnosticTextInfo::isClazyOption(option)) {
option = optionAsUtf8String.mid(8); // Remove "-Wclazy-" prefix.
return QString::fromUtf8(CLAZY_DOCUMENTATION_URL_TEMPLATE).arg(option);
}

View File

@@ -27,11 +27,20 @@
#include "clangconstants.h"
#include "clangdiagnostictooltipwidget.h"
#include "clangeditordocumentprocessor.h"
#include "clangmodelmanagersupport.h"
#include "clangprojectsettings.h"
#include "clangutils.h"
#include <utils/utilsicons.h>
#include <coreplugin/icore.h>
#include <cpptools/clangdiagnosticconfigsmodel.h>
#include <cpptools/cpptoolsreuse.h>
#include <cpptools/cppcodemodelsettings.h>
#include <utils/fadingindicator.h>
#include <utils/qtcassert.h>
#include <utils/theme/theme.h>
#include <utils/utilsicons.h>
#include <QAction>
#include <QApplication>
@@ -64,6 +73,102 @@ static Core::Id categoryForSeverity(ClangBackEnd::DiagnosticSeverity severity)
return isWarningOrNote(severity) ? Constants::CLANG_WARNING : Constants::CLANG_ERROR;
}
ProjectExplorer::Project *projectForCurrentEditor()
{
using namespace CppTools;
using namespace ClangCodeModel::Internal;
const QString filePath = Utils::currentCppEditorDocumentFilePath();
if (filePath.isEmpty())
return nullptr;
if (auto processor = ClangEditorDocumentProcessor::get(filePath)) {
if (ProjectPart::Ptr projectPart = processor->projectPart())
return projectPart->project;
}
return nullptr;
}
void disableDiagnosticInConfig(CppTools::ClangDiagnosticConfig &config,
const ClangBackEnd::DiagnosticContainer &diagnostic)
{
// Clang check
if (!diagnostic.disableOption.isEmpty()) {
config.setClangOptions(config.clangOptions() + QStringList(diagnostic.disableOption));
return;
}
// Clazy check
using namespace ClangCodeModel::Utils;
DiagnosticTextInfo textInfo(diagnostic.text);
if (DiagnosticTextInfo::isClazyOption(textInfo.option())) {
const QString checkName = DiagnosticTextInfo::clazyCheckName(textInfo.option());
QStringList newChecks = config.clazyChecks().split(',');
newChecks.removeOne(checkName);
config.setClazyChecks(newChecks.join(','));
return;
}
// Tidy check
config.setClangTidyChecks(config.clangTidyChecks() + QString(",-") + textInfo.option());
}
void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticContainer &diagnostic)
{
using namespace CppTools;
using namespace ClangCodeModel::Internal;
ProjectExplorer::Project *project = projectForCurrentEditor();
QTC_ASSERT(project, return );
// Get settings
ClangProjectSettings &projectSettings = ClangModelManagerSupport::instance()->projectSettings(
project);
const QSharedPointer<CppCodeModelSettings> globalSettings = codeModelSettings();
// Get config id
Core::Id currentConfigId = projectSettings.warningConfigId();
if (projectSettings.useGlobalConfig())
currentConfigId = globalSettings->clangDiagnosticConfigId();
// Get config
const ClangDiagnosticConfigs originalConfigs = globalSettings->clangCustomDiagnosticConfigs();
ClangDiagnosticConfigsModel configsModel(globalSettings->clangCustomDiagnosticConfigs());
QTC_ASSERT(configsModel.hasConfigWithId(currentConfigId), return );
ClangDiagnosticConfig config = configsModel.configWithId(currentConfigId);
// Create copy if needed
if (config.isReadOnly()) {
const QString name = QCoreApplication::translate("ClangDiagnosticConfig",
"Project: %1 (based on %2)")
.arg(project->displayName(), config.displayName());
config = ClangDiagnosticConfigsModel::createCustomConfig(config, name);
}
// Modify diagnostic config
disableDiagnosticInConfig(config, diagnostic);
configsModel.appendOrUpdate(config);
// Set global settings
globalSettings->setClangCustomDiagnosticConfigs(configsModel.customConfigs());
globalSettings->toSettings(Core::ICore::settings());
// Set project settings
if (projectSettings.useGlobalConfig())
projectSettings.setUseGlobalConfig(false);
projectSettings.setWarningConfigId(config.id());
projectSettings.store();
// Notify the user about changed project specific settings
const QString text
= QCoreApplication::translate("ClangDiagnosticConfig",
"Changes applied in Projects Mode > Clang Code Model");
::Utils::FadingIndicator::showText(Core::ICore::mainWindow(),
text,
::Utils::FadingIndicator::SmallText);
}
} // anonymous namespace
ClangTextMark::ClangTextMark(const FileName &fileName,
@@ -88,6 +193,8 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
: ::Utils::Theme::CodeModel_Error_TextMarkColor);
}
// Copy to clipboard action
QVector<QAction *> actions;
QAction *action = new QAction();
action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()));
QObject::connect(action, &QAction::triggered, [diagnostic]() {
@@ -96,7 +203,19 @@ ClangTextMark::ClangTextMark(const FileName &fileName,
ClangDiagnosticWidget::InfoBar);
QApplication::clipboard()->setText(text, QClipboard::Clipboard);
});
setActions({action});
actions << action;
// Remove diagnostic warning action
if (projectForCurrentEditor()) {
action = new QAction();
action->setIcon(::Utils::Icons::BROKEN.icon());
QObject::connect(action, &QAction::triggered, [diagnostic]() {
disableDiagnosticInCurrentProjectConfig(diagnostic);
});
actions << action;
}
setActions(actions);
}
void ClangTextMark::updateIcon(bool valid)

View File

@@ -373,5 +373,51 @@ QString currentCppEditorDocumentFilePath()
return filePath;
}
DiagnosticTextInfo::DiagnosticTextInfo(const QString &text)
: m_text(text)
, m_squareBracketStartIndex(text.lastIndexOf('['))
{}
QString DiagnosticTextInfo::textWithoutOption() const
{
if (m_squareBracketStartIndex == -1)
return m_text;
return m_text.mid(0, m_squareBracketStartIndex - 1);
}
QString DiagnosticTextInfo::option() const
{
if (m_squareBracketStartIndex == -1)
return QString();
const int index = m_squareBracketStartIndex + 1;
return m_text.mid(index, m_text.count() - index - 1);
}
QString DiagnosticTextInfo::category() const
{
if (m_squareBracketStartIndex == -1)
return QString();
const int index = m_squareBracketStartIndex + 1;
if (isClazyOption(m_text.mid(index)))
return QCoreApplication::translate("ClangDiagnosticWidget", "Clazy Issue");
else
return QCoreApplication::translate("ClangDiagnosticWidget", "Clang-Tidy Issue");
}
bool DiagnosticTextInfo::isClazyOption(const QString &option)
{
return option.startsWith("-Wclazy");
}
QString DiagnosticTextInfo::clazyCheckName(const QString &option)
{
if (option.startsWith("-Wclazy"))
return option.mid(8); // Chop "-Wclazy-"
return option;
}
} // namespace Utils
} // namespace Clang

View File

@@ -72,6 +72,23 @@ QString diagnosticCategoryPrefixRemoved(const QString &text);
void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo);
class DiagnosticTextInfo
{
public:
DiagnosticTextInfo(const QString &text);
QString textWithoutOption() const;
QString option() const;
QString category() const;
static bool isClazyOption(const QString &option);
static QString clazyCheckName(const QString &option);
private:
const QString m_text;
const int m_squareBracketStartIndex;
};
namespace Text {
template <class CharacterProvider>