2015-08-31 16:28:26 +02:00
|
|
|
/****************************************************************************
|
|
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** Copyright (C) 2016 The Qt Company Ltd.
|
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
2015-08-31 16:28:26 +02:00
|
|
|
**
|
|
|
|
|
** 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
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2015-08-31 16:28:26 +02:00
|
|
|
**
|
2016-01-15 14:57:40 +01:00
|
|
|
** 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.
|
2015-08-31 16:28:26 +02:00
|
|
|
**
|
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#include "clangtextmark.h"
|
|
|
|
|
|
2015-11-30 09:43:50 +01:00
|
|
|
#include "clangconstants.h"
|
2016-07-22 08:57:32 +02:00
|
|
|
#include "clangdiagnostictooltipwidget.h"
|
2019-01-28 12:40:03 +01:00
|
|
|
#include "clangeditordocumentprocessor.h"
|
|
|
|
|
#include "clangmodelmanagersupport.h"
|
|
|
|
|
#include "clangprojectsettings.h"
|
2018-05-09 15:12:01 +02:00
|
|
|
#include "clangutils.h"
|
2015-08-31 16:28:26 +02:00
|
|
|
|
2019-01-28 12:40:03 +01:00
|
|
|
#include <coreplugin/icore.h>
|
|
|
|
|
#include <cpptools/clangdiagnosticconfigsmodel.h>
|
|
|
|
|
#include <cpptools/cpptoolsreuse.h>
|
|
|
|
|
#include <cpptools/cppcodemodelsettings.h>
|
|
|
|
|
|
|
|
|
|
#include <utils/fadingindicator.h>
|
2016-11-17 15:55:06 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2016-02-02 14:54:31 +01:00
|
|
|
#include <utils/theme/theme.h>
|
2019-01-28 12:40:03 +01:00
|
|
|
#include <utils/utilsicons.h>
|
2015-08-31 16:28:26 +02:00
|
|
|
|
2019-01-28 09:32:11 +01:00
|
|
|
#include <QAction>
|
2017-06-01 08:48:11 +02:00
|
|
|
#include <QApplication>
|
2019-01-28 09:32:11 +01:00
|
|
|
#include <QClipboard>
|
2016-10-18 18:01:57 +02:00
|
|
|
#include <QLayout>
|
2015-08-31 16:28:26 +02:00
|
|
|
#include <QString>
|
|
|
|
|
|
2019-02-15 15:03:52 +01:00
|
|
|
using namespace CppTools;
|
|
|
|
|
using namespace ClangCodeModel::Internal;
|
2018-05-02 15:02:00 +02:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2015-08-31 16:28:26 +02:00
|
|
|
namespace ClangCodeModel {
|
2019-02-06 16:17:03 +01:00
|
|
|
namespace Internal {
|
2015-08-31 16:28:26 +02:00
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
bool isWarningOrNote(ClangBackEnd::DiagnosticSeverity severity)
|
|
|
|
|
{
|
|
|
|
|
using ClangBackEnd::DiagnosticSeverity;
|
|
|
|
|
switch (severity) {
|
|
|
|
|
case DiagnosticSeverity::Ignored:
|
|
|
|
|
case DiagnosticSeverity::Note:
|
|
|
|
|
case DiagnosticSeverity::Warning: return true;
|
2015-09-21 16:09:53 +02:00
|
|
|
case DiagnosticSeverity::Error:
|
|
|
|
|
case DiagnosticSeverity::Fatal: return false;
|
2015-08-31 16:28:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Q_UNREACHABLE();
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-12 00:13:48 +03:00
|
|
|
static Core::Id categoryForSeverity(ClangBackEnd::DiagnosticSeverity severity)
|
2015-08-31 16:28:26 +02:00
|
|
|
{
|
|
|
|
|
return isWarningOrNote(severity) ? Constants::CLANG_WARNING : Constants::CLANG_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-28 12:40:03 +01:00
|
|
|
ProjectExplorer::Project *projectForCurrentEditor()
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-15 15:05:02 +01:00
|
|
|
enum class DiagnosticType { Clang, Tidy, Clazy };
|
|
|
|
|
DiagnosticType diagnosticType(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
if (!diagnostic.disableOption.isEmpty())
|
|
|
|
|
return DiagnosticType::Clang;
|
|
|
|
|
|
|
|
|
|
const Utils::DiagnosticTextInfo textInfo(diagnostic.text);
|
|
|
|
|
if (Utils::DiagnosticTextInfo::isClazyOption(textInfo.option()))
|
|
|
|
|
return DiagnosticType::Clazy;
|
|
|
|
|
return DiagnosticType::Tidy;
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-15 15:03:52 +01:00
|
|
|
void disableDiagnosticInConfig(ClangDiagnosticConfig &config,
|
2019-01-28 12:40:03 +01:00
|
|
|
const ClangBackEnd::DiagnosticContainer &diagnostic)
|
|
|
|
|
{
|
|
|
|
|
using namespace ClangCodeModel::Utils;
|
2019-02-15 15:05:02 +01:00
|
|
|
|
|
|
|
|
switch (diagnosticType(diagnostic)) {
|
|
|
|
|
case DiagnosticType::Clang:
|
|
|
|
|
config.setClangOptions(config.clangOptions() + QStringList(diagnostic.disableOption));
|
|
|
|
|
break;
|
|
|
|
|
case DiagnosticType::Tidy:
|
|
|
|
|
config.setClangTidyChecks(config.clangTidyChecks() + QString(",-")
|
|
|
|
|
+ DiagnosticTextInfo(diagnostic.text).option());
|
|
|
|
|
break;
|
|
|
|
|
case DiagnosticType::Clazy: {
|
|
|
|
|
const DiagnosticTextInfo textInfo(diagnostic.text);
|
2019-01-28 12:40:03 +01:00
|
|
|
const QString checkName = DiagnosticTextInfo::clazyCheckName(textInfo.option());
|
|
|
|
|
QStringList newChecks = config.clazyChecks().split(',');
|
|
|
|
|
newChecks.removeOne(checkName);
|
|
|
|
|
config.setClazyChecks(newChecks.join(','));
|
2019-02-15 15:05:02 +01:00
|
|
|
break;
|
|
|
|
|
}
|
2019-01-28 12:40:03 +01:00
|
|
|
}
|
2019-02-15 15:05:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClangDiagnosticConfig diagnosticConfig(ClangProjectSettings &projectSettings,
|
|
|
|
|
CppCodeModelSettings &globalSettings)
|
|
|
|
|
{
|
|
|
|
|
ProjectExplorer::Project *project = projectForCurrentEditor();
|
|
|
|
|
QTC_ASSERT(project, return {});
|
|
|
|
|
|
|
|
|
|
// Get config id
|
|
|
|
|
Core::Id currentConfigId = projectSettings.warningConfigId();
|
|
|
|
|
if (projectSettings.useGlobalConfig())
|
|
|
|
|
currentConfigId = globalSettings.clangDiagnosticConfigId();
|
2019-01-28 12:40:03 +01:00
|
|
|
|
2019-02-15 15:05:02 +01:00
|
|
|
// Get config
|
|
|
|
|
ClangDiagnosticConfigsModel configsModel(globalSettings.clangCustomDiagnosticConfigs());
|
|
|
|
|
QTC_ASSERT(configsModel.hasConfigWithId(currentConfigId), return {});
|
|
|
|
|
return configsModel.configWithId(currentConfigId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isDiagnosticConfigChangable(ProjectExplorer::Project *project,
|
|
|
|
|
const ClangBackEnd::DiagnosticContainer &diagnostic)
|
|
|
|
|
{
|
|
|
|
|
if (!project)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
ClangProjectSettings &projectSettings = ClangModelManagerSupport::instance()->projectSettings(
|
|
|
|
|
project);
|
|
|
|
|
const QSharedPointer<CppCodeModelSettings> globalSettings = codeModelSettings();
|
|
|
|
|
const ClangDiagnosticConfig config = diagnosticConfig(projectSettings, *globalSettings);
|
|
|
|
|
|
|
|
|
|
if (config.clangTidyMode() == ClangDiagnosticConfig::TidyMode::File
|
|
|
|
|
&& diagnosticType(diagnostic) == DiagnosticType::Tidy) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2019-01-28 12:40:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void disableDiagnosticInCurrentProjectConfig(const ClangBackEnd::DiagnosticContainer &diagnostic)
|
|
|
|
|
{
|
|
|
|
|
ProjectExplorer::Project *project = projectForCurrentEditor();
|
|
|
|
|
QTC_ASSERT(project, return );
|
|
|
|
|
|
|
|
|
|
// Get settings
|
|
|
|
|
ClangProjectSettings &projectSettings = ClangModelManagerSupport::instance()->projectSettings(
|
|
|
|
|
project);
|
|
|
|
|
const QSharedPointer<CppCodeModelSettings> globalSettings = codeModelSettings();
|
|
|
|
|
|
|
|
|
|
// Get config
|
2019-02-15 15:05:02 +01:00
|
|
|
ClangDiagnosticConfig config = diagnosticConfig(projectSettings, *globalSettings);
|
2019-01-28 12:40:03 +01:00
|
|
|
ClangDiagnosticConfigsModel configsModel(globalSettings->clangCustomDiagnosticConfigs());
|
|
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-31 16:28:26 +02:00
|
|
|
} // anonymous namespace
|
|
|
|
|
|
2019-05-28 13:49:26 +02:00
|
|
|
ClangTextMark::ClangTextMark(const FilePath &fileName,
|
2016-11-17 15:55:06 +01:00
|
|
|
const ClangBackEnd::DiagnosticContainer &diagnostic,
|
2017-07-10 09:53:34 +02:00
|
|
|
const RemovedFromEditorHandler &removedHandler,
|
2018-05-09 13:37:51 +02:00
|
|
|
bool fullVisualization)
|
2016-11-17 15:55:06 +01:00
|
|
|
: TextEditor::TextMark(fileName,
|
2018-04-04 18:25:23 +02:00
|
|
|
int(diagnostic.location.line),
|
2018-04-12 00:13:48 +03:00
|
|
|
categoryForSeverity(diagnostic.severity))
|
2016-11-17 15:55:06 +01:00
|
|
|
, m_diagnostic(diagnostic)
|
|
|
|
|
, m_removedFromEditorHandler(removedHandler)
|
2015-08-31 16:28:26 +02:00
|
|
|
{
|
2018-04-04 18:25:23 +02:00
|
|
|
const bool warning = isWarningOrNote(diagnostic.severity);
|
2017-06-01 08:48:11 +02:00
|
|
|
setDefaultToolTip(warning ? QApplication::translate("Clang Code Model Marks", "Code Model Warning")
|
|
|
|
|
: QApplication::translate("Clang Code Model Marks", "Code Model Error"));
|
|
|
|
|
setPriority(warning ? TextEditor::TextMark::NormalPriority
|
|
|
|
|
: TextEditor::TextMark::HighPriority);
|
2017-07-03 13:29:30 +02:00
|
|
|
updateIcon();
|
2018-05-09 13:37:51 +02:00
|
|
|
if (fullVisualization) {
|
2018-05-09 15:12:01 +02:00
|
|
|
setLineAnnotation(Utils::diagnosticCategoryPrefixRemoved(diagnostic.text.toString()));
|
2018-05-16 10:32:08 +02:00
|
|
|
setColor(warning ? ::Utils::Theme::CodeModel_Warning_TextMarkColor
|
|
|
|
|
: ::Utils::Theme::CodeModel_Error_TextMarkColor);
|
2018-05-09 13:37:51 +02:00
|
|
|
}
|
2019-01-28 09:32:11 +01:00
|
|
|
|
2019-01-28 12:40:03 +01:00
|
|
|
// Copy to clipboard action
|
|
|
|
|
QVector<QAction *> actions;
|
2019-01-28 09:32:11 +01:00
|
|
|
QAction *action = new QAction();
|
|
|
|
|
action->setIcon(QIcon::fromTheme("edit-copy", ::Utils::Icons::COPY.icon()));
|
|
|
|
|
QObject::connect(action, &QAction::triggered, [diagnostic]() {
|
|
|
|
|
const QString text = ClangDiagnosticWidget::createText({diagnostic},
|
|
|
|
|
ClangDiagnosticWidget::InfoBar);
|
|
|
|
|
QApplication::clipboard()->setText(text, QClipboard::Clipboard);
|
|
|
|
|
});
|
2019-01-28 12:40:03 +01:00
|
|
|
actions << action;
|
|
|
|
|
|
|
|
|
|
// Remove diagnostic warning action
|
2019-02-15 15:05:02 +01:00
|
|
|
ProjectExplorer::Project *project = projectForCurrentEditor();
|
|
|
|
|
if (project && isDiagnosticConfigChangable(project, diagnostic)) {
|
2019-01-28 12:40:03 +01:00
|
|
|
action = new QAction();
|
|
|
|
|
action->setIcon(::Utils::Icons::BROKEN.icon());
|
|
|
|
|
QObject::connect(action, &QAction::triggered, [diagnostic]() {
|
|
|
|
|
disableDiagnosticInCurrentProjectConfig(diagnostic);
|
|
|
|
|
});
|
|
|
|
|
actions << action;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
setActions(actions);
|
2015-09-21 16:09:53 +02:00
|
|
|
}
|
|
|
|
|
|
2017-07-03 13:29:30 +02:00
|
|
|
void ClangTextMark::updateIcon(bool valid)
|
2015-09-21 16:09:53 +02:00
|
|
|
{
|
2018-05-09 15:12:01 +02:00
|
|
|
using namespace ::Utils::Icons;
|
2018-04-04 18:25:23 +02:00
|
|
|
if (isWarningOrNote(m_diagnostic.severity))
|
2017-11-16 08:25:31 +01:00
|
|
|
setIcon(valid ? CODEMODEL_WARNING.icon() : CODEMODEL_DISABLED_WARNING.icon());
|
2015-09-21 16:09:53 +02:00
|
|
|
else
|
2017-11-16 08:25:31 +01:00
|
|
|
setIcon(valid ? CODEMODEL_ERROR.icon() : CODEMODEL_DISABLED_ERROR.icon());
|
2015-08-31 16:28:26 +02:00
|
|
|
}
|
|
|
|
|
|
2017-06-20 08:28:10 +02:00
|
|
|
bool ClangTextMark::addToolTipContent(QLayout *target) const
|
2016-07-22 08:57:32 +02:00
|
|
|
{
|
2019-01-28 11:43:18 +01:00
|
|
|
QWidget *widget = ClangDiagnosticWidget::createWidget({m_diagnostic},
|
|
|
|
|
ClangDiagnosticWidget::ToolTip);
|
2016-10-18 18:01:57 +02:00
|
|
|
target->addWidget(widget);
|
|
|
|
|
|
2016-08-16 14:19:41 +02:00
|
|
|
return true;
|
2016-07-22 08:57:32 +02:00
|
|
|
}
|
|
|
|
|
|
2016-11-17 15:55:06 +01:00
|
|
|
void ClangTextMark::removedFromEditor()
|
|
|
|
|
{
|
|
|
|
|
QTC_ASSERT(m_removedFromEditorHandler, return);
|
|
|
|
|
m_removedFromEditorHandler(this);
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-06 16:17:03 +01:00
|
|
|
} // namespace Internal
|
2015-08-31 16:28:26 +02:00
|
|
|
} // namespace ClangCodeModel
|
|
|
|
|
|