From fa1862c7822f094c6475ed1cdda479bf815f4451 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 1 Feb 2019 14:08:02 +0100 Subject: [PATCH 01/16] LSP: move text marks from the manager to the individual clients MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Diagnostics are “owned” by the server so it is the server’s responsibility to clear them if necessary. So do not delete the corresponding text mark after a file was closed, because the server does not have to resend the diagnostics when the file is reopened. Only delete text marks when they are replaced or when the client is deleted or reset. Change-Id: Ief821c7ec401f4c52ee30d99f8dec47dcd6f1c98 Reviewed-by: Christian Stenger --- src/plugins/languageclient/client.cpp | 65 +++++++++++++- src/plugins/languageclient/client.h | 19 ++-- .../languageclient/languageclientmanager.cpp | 89 ------------------- .../languageclient/languageclientmanager.h | 9 -- 4 files changed, 77 insertions(+), 105 deletions(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 7ac2bd646fc..f6ebaa047f8 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -39,11 +39,13 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include @@ -62,6 +64,25 @@ namespace LanguageClient { static Q_LOGGING_CATEGORY(LOGLSPCLIENT, "qtc.languageclient.client", QtWarningMsg); +class TextMark : public TextEditor::TextMark +{ +public: + TextMark(const Utils::FileName &fileName, const Diagnostic &diag) + : TextEditor::TextMark(fileName, diag.range().start().line() + 1, "lspmark") + { + using namespace Utils; + setLineAnnotation(diag.message()); + setToolTip(diag.message()); + const bool isError + = diag.severity().value_or(DiagnosticSeverity::Hint) == DiagnosticSeverity::Error; + setColor(isError ? Theme::CodeModel_Error_TextMarkColor + : Theme::CodeModel_Warning_TextMarkColor); + + setIcon(isError ? Icons::CODEMODEL_ERROR.icon() + : Icons::CODEMODEL_WARNING.icon()); + } +}; + Client::Client(BaseClientInterface *clientInterface) : m_id(Core::Id::fromString(QUuid::createUuid().toString())) , m_completionProvider(this) @@ -88,6 +109,8 @@ Client::~Client() widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id())); } } + for (const DocumentUri &uri : m_diagnostics.keys()) + removeDiagnostics(uri); } void Client::initialize() @@ -155,10 +178,12 @@ void Client::openDocument(Core::IDocument *document) return; } } + auto uri = DocumentUri::fromFileName(filePath); + showDiagnostics(uri); auto textDocument = qobject_cast(document); TextDocumentItem item; item.setLanguageId(TextDocumentItem::mimeTypeToLanguageId(document->mimeType())); - item.setUri(DocumentUri::fromFileName(filePath)); + item.setUri(uri); item.setText(QString::fromUtf8(document->contents())); item.setVersion(textDocument ? textDocument->document()->revision() : 0); @@ -672,6 +697,8 @@ bool Client::reset() m_openedDocument.clear(); m_serverCapabilities = ServerCapabilities(); m_dynamicCapabilities.reset(); + for (const DocumentUri &uri : m_diagnostics.keys()) + removeDiagnostics(uri); return true; } @@ -748,6 +775,25 @@ void Client::showMessageBox(const ShowMessageRequestParams &message, const Messa box->show(); } +void Client::showDiagnostics(const DocumentUri &uri) +{ + if (TextEditor::TextDocument *doc = textDocumentForFileName(uri.toFileName())) { + for (TextMark *mark : m_diagnostics.value(uri)) + doc->addMark(mark); + } +} + +void Client::removeDiagnostics(const DocumentUri &uri) +{ + TextEditor::TextDocument *doc = textDocumentForFileName(uri.toFileName()); + + for (TextMark *mark : m_diagnostics.take(uri)) { + if (doc) + doc->removeMark(mark); + delete mark; + } +} + void Client::handleResponse(const MessageId &id, const QByteArray &content, QTextCodec *codec) { if (auto handler = m_responseHandlers[id]) @@ -762,7 +808,7 @@ void Client::handleMethod(const QString &method, MessageId id, const IContent *c auto params = dynamic_cast(content)->params().value_or(PublishDiagnosticsParams()); paramsValid = params.isValid(&error); if (paramsValid) - LanguageClientManager::publishDiagnostics(m_id, params, this); + handleDiagnostics(params); } else if (method == LogMessageNotification::methodName) { auto params = dynamic_cast(content)->params().value_or(LogMessageParams()); paramsValid = params.isValid(&error); @@ -822,6 +868,21 @@ void Client::handleMethod(const QString &method, MessageId id, const IContent *c delete content; } +void Client::handleDiagnostics(const PublishDiagnosticsParams ¶ms) +{ + const DocumentUri &uri = params.uri(); + + removeDiagnostics(uri); + const QList &diagnostics = params.diagnostics(); + m_diagnostics[uri] = + Utils::transform(diagnostics, [fileName = uri.toFileName()](const Diagnostic &diagnostic) { + return new TextMark(fileName, diagnostic); + }); + showDiagnostics(uri); + + requestCodeActions(uri, diagnostics); +} + void Client::intializeCallback(const InitializeRequest::Response &initResponse) { QTC_ASSERT(m_state == InitializeRequested, return); diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 6ae4166d2d1..3d691f2bd25 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -33,12 +33,13 @@ #include #include +#include +#include #include +#include +#include #include #include -#include -#include -#include #include #include @@ -50,13 +51,15 @@ namespace Core { class IDocument; } namespace ProjectExplorer { class Project; } namespace TextEditor { - class TextDocument; - class TextEditorWidget; +class TextDocument; +class TextEditorWidget; +class TextMark; } namespace LanguageClient { class BaseClientInterface; +class TextMark; class Client : public QObject { @@ -153,6 +156,8 @@ private: void handleMethod(const QString &method, LanguageServerProtocol::MessageId id, const LanguageServerProtocol::IContent *content); + void handleDiagnostics(const LanguageServerProtocol::PublishDiagnosticsParams ¶ms); + void intializeCallback(const LanguageServerProtocol::InitializeRequest::Response &initResponse); void shutDownCallback(const LanguageServerProtocol::ShutdownRequest::Response &shutdownResponse); bool sendWorkspceFolderChanges() const; @@ -162,6 +167,9 @@ private: void showMessageBox(const LanguageServerProtocol::ShowMessageRequestParams &message, const LanguageServerProtocol::MessageId &id); + void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri); + void removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri); + using ContentHandler = std::function; @@ -180,6 +188,7 @@ private: QHash m_highlightRequests; int m_restartsLeft = 5; QScopedPointer m_clientInterface; + QMap> m_diagnostics; }; } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 3e0e25e66c5..22261e62730 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -49,30 +49,6 @@ namespace LanguageClient { static LanguageClientManager *managerInstance = nullptr; -class LanguageClientMark : public TextEditor::TextMark -{ -public: - LanguageClientMark(const Utils::FileName &fileName, const Diagnostic &diag) - : TextEditor::TextMark(fileName, diag.range().start().line() + 1, "lspmark") - { - using namespace Utils; - setLineAnnotation(diag.message()); - setToolTip(diag.message()); - const bool isError - = diag.severity().value_or(DiagnosticSeverity::Hint) == DiagnosticSeverity::Error; - setColor(isError ? Theme::CodeModel_Error_TextMarkColor - : Theme::CodeModel_Warning_TextMarkColor); - - setIcon(isError ? Icons::CODEMODEL_ERROR.icon() - : Icons::CODEMODEL_WARNING.icon()); - } - - void removedFromEditor() override - { - LanguageClientManager::removeMark(this); - } -}; - LanguageClientManager::LanguageClientManager() { JsonRpcMessageHandler::registerMessageProvider(); @@ -107,68 +83,6 @@ void LanguageClientManager::init() managerInstance, &LanguageClientManager::projectRemoved); } -void LanguageClientManager::publishDiagnostics(const Core::Id &id, - const PublishDiagnosticsParams ¶ms, - Client *publishingClient) -{ - const Utils::FileName fileName = params.uri().toFileName(); - TextEditor::TextDocument *doc = textDocumentForFileName(fileName); - if (!doc) - return; - - removeMarks(fileName, id); - managerInstance->m_marks[fileName][id].reserve(params.diagnostics().size()); - QList diagnostics = params.diagnostics(); - for (const Diagnostic& diagnostic : diagnostics) { - auto mark = new LanguageClientMark(fileName, diagnostic); - managerInstance->m_marks[fileName][id].append(mark); - doc->addMark(mark); - } - - publishingClient->requestCodeActions(params.uri(), diagnostics); -} - -void LanguageClientManager::removeMark(LanguageClientMark *mark) -{ - for (auto &marks : managerInstance->m_marks[mark->fileName()]) - marks.removeAll(mark); - delete mark; -} - -void LanguageClientManager::removeMarks(const Utils::FileName &fileName) -{ - TextEditor::TextDocument *doc = textDocumentForFileName(fileName); - if (!doc) - return; - - for (const auto &marks : qAsConst(managerInstance->m_marks[fileName])) { - for (TextEditor::TextMark *mark : marks) { - doc->removeMark(mark); - delete mark; - } - } - managerInstance->m_marks[fileName].clear(); -} - -void LanguageClientManager::removeMarks(const Utils::FileName &fileName, const Core::Id &id) -{ - TextEditor::TextDocument *doc = textDocumentForFileName(fileName); - if (!doc) - return; - - for (TextEditor::TextMark *mark : managerInstance->m_marks[fileName][id]) { - doc->removeMark(mark); - delete mark; - } - managerInstance->m_marks[fileName][id].clear(); -} - -void LanguageClientManager::removeMarks(const Core::Id &id) -{ - for (const Utils::FileName &fileName : managerInstance->m_marks.keys()) - removeMarks(fileName, id); -} - void LanguageClientManager::startClient(Client *client) { QTC_ASSERT(client, return); @@ -210,7 +124,6 @@ void LanguageClientManager::deleteClient(Client *client) { QTC_ASSERT(client, return); client->disconnect(); - managerInstance->removeMarks(client->id()); managerInstance->m_clients.removeAll(client); client->deleteLater(); } @@ -269,7 +182,6 @@ void LanguageClientManager::clientFinished(Client *client) const bool unexpectedFinish = client->state() != Client::Shutdown && client->state() != Client::ShutdownRequested; if (unexpectedFinish && !m_shuttingDown && client->reset()) { - removeMarks(client->id()); client->disconnect(this); client->log(tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS), Core::MessageManager::Flash); @@ -312,7 +224,6 @@ void LanguageClientManager::editorsClosed(const QList &editors) { for (auto iEditor : editors) { if (auto editor = qobject_cast(iEditor)) { - removeMarks(editor->document()->filePath()); const DidCloseTextDocumentParams params(TextDocumentIdentifier( DocumentUri::fromFileName(editor->document()->filePath()))); for (Client *interface : reachableClients()) diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index d062a0bdff9..6adf1bd7732 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -55,14 +55,6 @@ public: static void init(); - static void publishDiagnostics(const Core::Id &id, - const LanguageServerProtocol::PublishDiagnosticsParams ¶ms, Client *publishingClient); - - static void removeMark(LanguageClientMark *mark); - static void removeMarks(const Utils::FileName &fileName); - static void removeMarks(const Utils::FileName &fileName, const Core::Id &id); - static void removeMarks(const Core::Id &id); - static void startClient(Client *client); static QVector clients(); @@ -101,7 +93,6 @@ private: bool m_shuttingDown = false; QVector m_clients; - QHash>> m_marks; QHash> m_exclusiveRequests; friend class LanguageClientPlugin; From 4e6b284e8b08341e4181adc89423369094cd9850 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 4 Feb 2019 13:05:11 +0100 Subject: [PATCH 02/16] QmlDesigner: Fix qbs build Change-Id: I6707f71832abc23e9c9df3012b242ce1fb54b830 Reviewed-by: David Schulz --- .../timelineeditor/timelinesettingsdialog.cpp | 1 + src/plugins/qmldesigner/qmldesignerplugin.qbs | 73 ++++++++++++++++++- 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsdialog.cpp b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsdialog.cpp index 51edc4d5111..b2bcb8565d2 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsdialog.cpp +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsdialog.cpp @@ -43,6 +43,7 @@ #include #include +#include #include namespace QmlDesigner { diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index cf78f1409bb..3360a532140 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -27,7 +27,11 @@ Project { Depends { name: "QtSupport" } Depends { name: "app_version_header" } - cpp.defines: base.concat("DESIGNER_CORE_LIBRARY") + cpp.defines: base.concat([ + "DESIGNER_CORE_LIBRARY", + "TIMELINE_QML_PATH=\"" + FileInfo.joinPaths(path, "qmldesignerextension", + "timelineeditor", "qml") + "\"" + ]) cpp.enableExceptions: true cpp.includePaths: base.concat([ ".", @@ -51,6 +55,7 @@ Project { "components/texteditor", "qmldesignerextension", "qmldesignerextension/connectioneditor", + "qmldesignerextension/timelineeditor", ]) Properties { @@ -635,6 +640,72 @@ Project { "texttool/textedititemwidget.h", "texttool/texttool.cpp", "texttool/texttool.h", + "timelineeditor/canvas.cpp", + "timelineeditor/canvas.h", + "timelineeditor/canvasstyledialog.cpp", + "timelineeditor/canvasstyledialog.h", + "timelineeditor/easingcurve.cpp", + "timelineeditor/easingcurve.h", + "timelineeditor/easingcurvedialog.cpp", + "timelineeditor/easingcurvedialog.h", + "timelineeditor/preseteditor.cpp", + "timelineeditor/preseteditor.h", + "timelineeditor/setframevaluedialog.cpp", + "timelineeditor/setframevaluedialog.h", + "timelineeditor/setframevaluedialog.ui", + "timelineeditor/splineeditor.cpp", + "timelineeditor/splineeditor.h", + "timelineeditor/timeline.qrc", + "timelineeditor/timelineabstracttool.cpp", + "timelineeditor/timelineabstracttool.h", + "timelineeditor/timelineactions.cpp", + "timelineeditor/timelineactions.h", + "timelineeditor/timelineanimationform.cpp", + "timelineeditor/timelineanimationform.h", + "timelineeditor/timelineanimationform.ui", + "timelineeditor/timelineconstants.h", + "timelineeditor/timelinecontext.cpp", + "timelineeditor/timelinecontext.h", + "timelineeditor/timelinecontrols.cpp", + "timelineeditor/timelinecontrols.h", + "timelineeditor/timelineform.cpp", + "timelineeditor/timelineform.h", + "timelineeditor/timelineform.ui", + "timelineeditor/timelinegraphicslayout.cpp", + "timelineeditor/timelinegraphicslayout.h", + "timelineeditor/timelinegraphicsscene.cpp", + "timelineeditor/timelinegraphicsscene.h", + "timelineeditor/timelineicons.h", + "timelineeditor/timelineitem.cpp", + "timelineeditor/timelineitem.h", + "timelineeditor/timelinemovableabstractitem.cpp", + "timelineeditor/timelinemovableabstractitem.h", + "timelineeditor/timelinemovetool.cpp", + "timelineeditor/timelinemovetool.h", + "timelineeditor/timelineplaceholder.cpp", + "timelineeditor/timelineplaceholder.h", + "timelineeditor/timelinepropertyitem.cpp", + "timelineeditor/timelinepropertyitem.h", + "timelineeditor/timelinesectionitem.cpp", + "timelineeditor/timelinesectionitem.h", + "timelineeditor/timelineselectiontool.cpp", + "timelineeditor/timelineselectiontool.h", + "timelineeditor/timelinesettingsdialog.cpp", + "timelineeditor/timelinesettingsdialog.h", + "timelineeditor/timelinesettingsdialog.ui", + "timelineeditor/timelinesettingsmodel.cpp", + "timelineeditor/timelinesettingsmodel.h", + "timelineeditor/timelinetoolbar.cpp", + "timelineeditor/timelinetoolbar.h", + "timelineeditor/timelinetoolbutton.cpp", + "timelineeditor/timelinetoolbutton.h", + "timelineeditor/timelinetooldelegate.cpp", + "timelineeditor/timelineutils.cpp", + "timelineeditor/timelineutils.h", + "timelineeditor/timelineview.cpp", + "timelineeditor/timelineview.h", + "timelineeditor/timelinewidget.cpp", + "timelineeditor/timelinewidget.h", ] } From b93f21d87a9b834a7f7cf21534fff99d66c64c75 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 31 Jan 2019 09:28:10 +0100 Subject: [PATCH 03/16] Debugger: Clarify role of "Executable:" in Load Core File dialog The file containing debug information is needed, this is typically the executable, but other setups are possible. Also make it a bit clearer in the code by using 'symbol' in a few places that previously used 'localExecutable'. Task-number: QTCREATORBUG-21910 Change-Id: I5c61bc03302c06baa58f82e1d5097f425f8936a8 Reviewed-by: Christian Stenger Reviewed-by: Leena Miettinen --- src/plugins/debugger/debuggerplugin.cpp | 6 ++-- src/plugins/debugger/loadcoredialog.cpp | 42 ++++++++++++++----------- src/plugins/debugger/loadcoredialog.h | 4 +-- 3 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 661400cb515..e52cb723141 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1561,7 +1561,7 @@ void DebuggerPluginPrivate::attachCore() const QString lastExternalKit = configValue("LastExternalKit").toString(); if (!lastExternalKit.isEmpty()) dlg.setKitId(Id::fromString(lastExternalKit)); - dlg.setLocalExecutableFile(configValue("LastExternalExecutableFile").toString()); + dlg.setSymbolFile(configValue("LastExternalExecutableFile").toString()); dlg.setLocalCoreFile(configValue("LastLocalCoreFile").toString()); dlg.setRemoteCoreFile(configValue("LastRemoteCoreFile").toString()); dlg.setOverrideStartScript(configValue("LastExternalStartScript").toString()); @@ -1570,7 +1570,7 @@ void DebuggerPluginPrivate::attachCore() if (dlg.exec() != QDialog::Accepted) return; - setConfigValue("LastExternalExecutableFile", dlg.localExecutableFile()); + setConfigValue("LastExternalExecutableFile", dlg.symbolFile()); setConfigValue("LastLocalCoreFile", dlg.localCoreFile()); setConfigValue("LastRemoteCoreFile", dlg.remoteCoreFile()); setConfigValue("LastExternalKit", dlg.kit()->id().toSetting()); @@ -1580,7 +1580,7 @@ void DebuggerPluginPrivate::attachCore() IDevice::ConstPtr device = DeviceKitInformation::device(dlg.kit()); auto runControl = new RunControl(device, ProjectExplorer::Constants::DEBUG_RUN_MODE); auto debugger = new DebuggerRunTool(runControl, dlg.kit()); - debugger->setInferiorExecutable(dlg.localExecutableFile()); + debugger->setInferiorExecutable(dlg.symbolFile()); debugger->setCoreFileName(dlg.localCoreFile()); debugger->setRunControlName(tr("Core file \"%1\"") .arg(dlg.useLocalCoreFile() ? dlg.localCoreFile() : dlg.remoteCoreFile())); diff --git a/src/plugins/debugger/loadcoredialog.cpp b/src/plugins/debugger/loadcoredialog.cpp index 9221b9b5b63..8bd68aa791d 100644 --- a/src/plugins/debugger/loadcoredialog.cpp +++ b/src/plugins/debugger/loadcoredialog.cpp @@ -207,7 +207,7 @@ public: QCheckBox *forceLocalCheckBox; QLabel *forceLocalLabel; - PathChooser *localExecFileName; + PathChooser *symbolFileName; PathChooser *localCoreFileName; QLineEdit *remoteCoreFileName; QPushButton *selectRemoteCoreButton; @@ -220,11 +220,11 @@ public: { bool isValid() const { - return validKit && validLocalExecFilename && validCoreFilename; + return validKit && validSymbolFilename && validCoreFilename; } bool validKit; - bool validLocalExecFilename; + bool validSymbolFilename; bool validCoreFilename; bool localCoreFile; bool localKit; @@ -235,7 +235,7 @@ public: State st; st.localCoreFile = p.useLocalCoreFile(); st.validKit = (kitChooser->currentKit() != nullptr); - st.validLocalExecFilename = localExecFileName->isValid(); + st.validSymbolFilename = symbolFileName->isValid(); if (st.localCoreFile) st.validCoreFilename = localCoreFileName->isValid(); @@ -274,10 +274,14 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent) d->localCoreFileName->setExpectedKind(PathChooser::File); d->localCoreFileName->setPromptDialogTitle(tr("Select Core File")); - d->localExecFileName = new PathChooser(this); - d->localExecFileName->setHistoryCompleter("LocalExecutable"); - d->localExecFileName->setExpectedKind(PathChooser::File); - d->localExecFileName->setPromptDialogTitle(tr("Select Executable")); + d->symbolFileName = new PathChooser(this); + d->symbolFileName->setHistoryCompleter("LocalExecutable"); + d->symbolFileName->setExpectedKind(PathChooser::File); + d->symbolFileName->setPromptDialogTitle(tr("Select Executable or Symbol File")); + d->symbolFileName->setToolTip( + tr("Select a file containing debug information corresponding to the core file. " + "Typically, this is the executable or a *.debug file if the debug " + "information is stored separately from the executable.")); d->overrideStartScriptFileName = new PathChooser(this); d->overrideStartScriptFileName->setHistoryCompleter("Debugger.StartupScript.History"); @@ -296,7 +300,7 @@ AttachCoreDialog::AttachCoreDialog(QWidget *parent) formLayout->addRow(tr("Kit:"), d->kitChooser); formLayout->addRow(d->forceLocalLabel, d->forceLocalCheckBox); formLayout->addRow(tr("Core file:"), coreLayout); - formLayout->addRow(tr("&Executable:"), d->localExecFileName); + formLayout->addRow(tr("&Executable or symbol file:"), d->symbolFileName); formLayout->addRow(tr("Override &start script:"), d->overrideStartScriptFileName); auto line = new QFrame(this); @@ -321,7 +325,7 @@ int AttachCoreDialog::exec() { connect(d->selectRemoteCoreButton, &QAbstractButton::clicked, this, &AttachCoreDialog::selectRemoteCoreFile); connect(d->remoteCoreFileName, &QLineEdit::textChanged, this, &AttachCoreDialog::coreFileChanged); - connect(d->localExecFileName, &PathChooser::rawPathChanged, this, &AttachCoreDialog::changed); + connect(d->symbolFileName, &PathChooser::rawPathChanged, this, &AttachCoreDialog::changed); connect(d->localCoreFileName, &PathChooser::rawPathChanged, this, &AttachCoreDialog::coreFileChanged); connect(d->forceLocalCheckBox, &QCheckBox::stateChanged, this, &AttachCoreDialog::changed); connect(d->kitChooser, &KitChooser::currentIndexChanged, this, &AttachCoreDialog::changed); @@ -337,8 +341,8 @@ int AttachCoreDialog::exec() d->localCoreFileName->setFocus(); else d->remoteCoreFileName->setFocus(); - } else if (!st.validLocalExecFilename) { - d->localExecFileName->setFocus(); + } else if (!st.validSymbolFilename) { + d->symbolFileName->setFocus(); } return QDialog::exec(); @@ -366,9 +370,9 @@ void AttachCoreDialog::coreFileChanged(const QString &core) Runnable debugger = DebuggerKitInformation::runnable(k); CoreInfo cinfo = CoreInfo::readExecutableNameFromCore(debugger, core); if (!cinfo.foundExecutableName.isEmpty()) - d->localExecFileName->setFileName(FileName::fromString(cinfo.foundExecutableName)); - else if (!d->localExecFileName->isValid() && !cinfo.rawStringFromCore.isEmpty()) - d->localExecFileName->setFileName(FileName::fromString(cinfo.rawStringFromCore)); + d->symbolFileName->setFileName(FileName::fromString(cinfo.foundExecutableName)); + else if (!d->symbolFileName->isValid() && !cinfo.rawStringFromCore.isEmpty()) + d->symbolFileName->setFileName(FileName::fromString(cinfo.rawStringFromCore)); } changed(); } @@ -411,14 +415,14 @@ QString AttachCoreDialog::localCoreFile() const return d->localCoreFileName->path(); } -QString AttachCoreDialog::localExecutableFile() const +QString AttachCoreDialog::symbolFile() const { - return d->localExecFileName->path(); + return d->symbolFileName->path(); } -void AttachCoreDialog::setLocalExecutableFile(const QString &fileName) +void AttachCoreDialog::setSymbolFile(const QString &symbolFileName) { - d->localExecFileName->setPath(fileName); + d->symbolFileName->setPath(symbolFileName); } void AttachCoreDialog::setLocalCoreFile(const QString &fileName) diff --git a/src/plugins/debugger/loadcoredialog.h b/src/plugins/debugger/loadcoredialog.h index 84cfaf677e9..84ba46a4fd7 100644 --- a/src/plugins/debugger/loadcoredialog.h +++ b/src/plugins/debugger/loadcoredialog.h @@ -45,7 +45,7 @@ public: int exec() override; - QString localExecutableFile() const; + QString symbolFile() const; QString localCoreFile() const; QString remoteCoreFile() const; QString overrideStartScript() const; @@ -55,7 +55,7 @@ public: // For persistance. ProjectExplorer::Kit *kit() const; - void setLocalExecutableFile(const QString &executable); + void setSymbolFile(const QString &symbolFileName); void setLocalCoreFile(const QString &core); void setRemoteCoreFile(const QString &core); void setOverrideStartScript(const QString &scriptName); From 7cf3ea7255dbe2a373cd60d7a34540f09702834c Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 30 Jan 2019 08:28:22 +0100 Subject: [PATCH 04/16] AutoTest: Fix wrong encoding handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I309eae71aae0d4591b9eb20a524e4ce2bcee8d6b Reviewed-by: André Hartmann Reviewed-by: David Schulz --- src/plugins/autotest/qtest/qttestoutputreader.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index 97fb6dc3cf0..a74c24dccd0 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -188,9 +188,7 @@ void QtTestOutputReader::processXMLOutput(const QByteArray &outputLine) if (m_className.isEmpty() && outputLine.trimmed().isEmpty()) return; - // avoid encoding problems for Quick tests - m_xmlReader.addData(m_testType == TestType::QuickTest ? QString::fromLatin1(outputLine) - : QString::fromLocal8Bit(outputLine)); + m_xmlReader.addData(QString::fromUtf8(outputLine)); while (!m_xmlReader.atEnd()) { if (m_futureInterface.isCanceled()) return; From 107028dd198d92bf013e3e5e95f75344a7b73376 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 31 Jan 2019 12:47:03 +0100 Subject: [PATCH 05/16] TextEditor: Remove duplication when handling textmark tooltips Change-Id: I1df48c91a6248f3e8a5feb62bbcd7644d765eeab Reviewed-by: David Schulz --- src/plugins/texteditor/texteditor.cpp | 84 +++++++++++++++------------ 1 file changed, 48 insertions(+), 36 deletions(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 7f9ad3b5f33..6dd9004c774 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -563,6 +563,9 @@ public: void processTooltipRequest(const QTextCursor &c); bool processAnnotaionTooltipRequest(const QTextBlock &block, const QPoint &pos) const; + void showTextMarksToolTip(const QPoint &pos, + const TextMarks &marks, + const TextMark *mainTextMark = nullptr) const; void transformSelection(TransformationMethod method); void transformBlockSelection(TransformationMethod method); @@ -836,6 +839,47 @@ TextEditorWidgetPrivate::~TextEditorWidgetPrivate() delete m_highlightScrollBarController; } +void TextEditorWidgetPrivate::showTextMarksToolTip(const QPoint &pos, + const TextMarks &marks, + const TextMark *mainTextMark) const +{ + if (!mainTextMark && marks.isEmpty()) + return; // Nothing to show + + TextMarks allMarks = marks; + + auto layout = new QGridLayout; + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(2); + + if (mainTextMark) { + mainTextMark->addToToolTipLayout(layout); + if (allMarks.size() > 1) { + QFrame* separator = new QFrame(); + separator->setFrameShape(QFrame::HLine); + layout->addWidget(separator, layout->rowCount(), 0, 1, -1); + layout->addWidget(new QLabel(TextEditorWidget::tr("Other annotations:")), + layout->rowCount(), + 0, + 1, + -1); + } + } + + Utils::sort(allMarks, [](const TextMark *mark1, const TextMark *mark2) { + return mark1->priority() > mark2->priority(); + }); + + for (const TextMark *mark : qAsConst(allMarks)) { + if (mark != mainTextMark) + mark->addToToolTipLayout(layout); + } + + layout->addWidget(DisplaySettings::createAnnotationSettingsLink(), + layout->rowCount(), 0, 1, -1, Qt::AlignRight); + ToolTip::show(pos, layout, q); +} + } // namespace Internal /*! @@ -3516,33 +3560,7 @@ bool TextEditorWidgetPrivate::processAnnotaionTooltipRequest(const QTextBlock &b for (const AnnotationRect &annotationRect : m_annotationRects[block.blockNumber()]) { if (!annotationRect.rect.contains(pos)) continue; - - auto layout = new QGridLayout; - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(2); - annotationRect.mark->addToToolTipLayout(layout); - TextMarks marks = blockUserData->marks(); - if (marks.size() > 1) { - QFrame* separator = new QFrame(); - separator->setFrameShape(QFrame::HLine); - layout->addWidget(separator, layout->rowCount(), 0, 1, -1); - layout->addWidget(new QLabel(TextEditorWidget::tr("Other annotations:")), - layout->rowCount(), - 0, - 1, - -1); - - Utils::sort(marks, [](const TextMark* mark1, const TextMark* mark2){ - return mark1->priority() > mark2->priority(); - }); - for (const TextMark *mark : qAsConst(marks)) { - if (mark != annotationRect.mark) - mark->addToToolTipLayout(layout); - } - } - layout->addWidget(DisplaySettings::createAnnotationSettingsLink(), - layout->rowCount(), 0, 1, -1, Qt::AlignRight); - ToolTip::show(q->mapToGlobal(pos), layout, q); + showTextMarksToolTip(q->mapToGlobal(pos), blockUserData->marks(), annotationRect.mark); return true; } return false; @@ -5787,16 +5805,10 @@ void TextEditorWidget::extraAreaMouseEvent(QMouseEvent *e) int line = cursor.blockNumber() + 1; if (d->extraAreaPreviousMarkTooltipRequestedLine != line) { if (auto data = static_cast(cursor.block().userData())) { - if (data->marks().isEmpty()) { + if (data->marks().isEmpty()) ToolTip::hide(); - } else { - auto layout = new QGridLayout; - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(2); - foreach (TextMark *mark, data->marks()) - mark->addToToolTipLayout(layout); - ToolTip::show(mapToGlobal(e->pos()), layout, this); - } + else + d->showTextMarksToolTip(mapToGlobal(e->pos()), data->marks()); } } d->extraAreaPreviousMarkTooltipRequestedLine = line; From a5317cdaa51386eba406b65ab2d440d5b87a967d Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Fri, 1 Feb 2019 09:05:41 +0100 Subject: [PATCH 06/16] TextEditor: Polish separator in text mark tooltip Use one row instead of two for showing "Other annotations" and the separator line. Change-Id: I25234fc2fb49ccb71125a1cf762c89b668032b77 Reviewed-by: David Schulz --- src/plugins/texteditor/texteditor.cpp | 41 ++++++++++++++++++++------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 0fdb332b384..acf9072bc25 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -839,6 +839,35 @@ TextEditorWidgetPrivate::~TextEditorWidgetPrivate() delete m_highlightScrollBarController; } +static QFrame *createSeparator(const QString &styleSheet) +{ + QFrame* separator = new QFrame(); + separator->setStyleSheet(styleSheet); + separator->setFrameShape(QFrame::HLine); + QSizePolicy sizePolicy = separator->sizePolicy(); + sizePolicy.setHorizontalPolicy(QSizePolicy::MinimumExpanding); + separator->setSizePolicy(sizePolicy); + + return separator; +} + +static QLayout *createSeparatorLayout() +{ + QString styleSheet = "color: gray"; + + QFrame* separator1 = createSeparator(styleSheet); + QFrame* separator2 = createSeparator(styleSheet); + auto label = new QLabel(TextEditorWidget::tr("Other annotations")); + label->setStyleSheet(styleSheet); + + auto layout = new QHBoxLayout; + layout->addWidget(separator1); + layout->addWidget(label); + layout->addWidget(separator2); + + return layout; +} + void TextEditorWidgetPrivate::showTextMarksToolTip(const QPoint &pos, const TextMarks &marks, const TextMark *mainTextMark) const @@ -854,16 +883,8 @@ void TextEditorWidgetPrivate::showTextMarksToolTip(const QPoint &pos, if (mainTextMark) { mainTextMark->addToToolTipLayout(layout); - if (allMarks.size() > 1) { - QFrame* separator = new QFrame(); - separator->setFrameShape(QFrame::HLine); - layout->addWidget(separator, layout->rowCount(), 0, 1, -1); - layout->addWidget(new QLabel(TextEditorWidget::tr("Other annotations:")), - layout->rowCount(), - 0, - 1, - -1); - } + if (allMarks.size() > 1) + layout->addLayout(createSeparatorLayout(), layout->rowCount(), 0, 1, -1); } Utils::sort(allMarks, [](const TextMark *mark1, const TextMark *mark2) { From 1a58a30685a7acb386989f8edbcd497d9472acf1 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 1 Feb 2019 12:24:56 +0100 Subject: [PATCH 07/16] AutoTest: Allow grouping of results by application Add an option to group test results by the application that contains the test cases. Fixes: QTCREATORBUG-21740 Change-Id: If4e5c8118cd5dd81b1b75891b4eca85b08e76848 Reviewed-by: Leena Miettinen Reviewed-by: David Schulz --- src/plugins/autotest/testresult.cpp | 3 ++ src/plugins/autotest/testresult.h | 2 ++ src/plugins/autotest/testresultmodel.cpp | 35 +++++++++++++++++++++-- src/plugins/autotest/testsettings.cpp | 3 ++ src/plugins/autotest/testsettings.h | 1 + src/plugins/autotest/testsettingspage.cpp | 2 ++ src/plugins/autotest/testsettingspage.ui | 9 +++++- 7 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/plugins/autotest/testresult.cpp b/src/plugins/autotest/testresult.cpp index 11d4ecb9365..ea4261a4536 100644 --- a/src/plugins/autotest/testresult.cpp +++ b/src/plugins/autotest/testresult.cpp @@ -55,6 +55,8 @@ TestResult::TestResult(const QString &id, const QString &name) const QString TestResult::outputString(bool selected) const { + if (m_result == Result::Application) + return m_id; return selected ? m_description : m_description.split('\n').first(); } @@ -145,6 +147,7 @@ QString TestResult::resultToString(const Result::Type type) case Result::BlacklistedXFail: return QString("BXFAIL"); case Result::MessageLocation: + case Result::Application: return QString(); default: if (type >= Result::INTERNAL_MESSAGES_BEGIN && type <= Result::INTERNAL_MESSAGES_END) diff --git a/src/plugins/autotest/testresult.h b/src/plugins/autotest/testresult.h index 2632be9e309..a1e1d2e7bf1 100644 --- a/src/plugins/autotest/testresult.h +++ b/src/plugins/autotest/testresult.h @@ -67,6 +67,8 @@ enum Type { MessageIntermediate, MessageCurrentTest, INTERNAL_MESSAGES_END = MessageCurrentTest, + Application, + Invalid, LAST_TYPE = Invalid }; diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp index 6cabd39cbcf..0a1ee0c6169 100644 --- a/src/plugins/autotest/testresultmodel.cpp +++ b/src/plugins/autotest/testresultmodel.cpp @@ -24,9 +24,12 @@ ****************************************************************************/ #include "autotesticons.h" +#include "autotestplugin.h" #include "testresultdelegate.h" #include "testresultmodel.h" +#include "testsettings.h" +#include #include #include @@ -62,6 +65,7 @@ static QIcon testResultIcon(Result::Type result) { QIcon(), Icons::RESULT_MESSAGEPASSWARN.icon(), Icons::RESULT_MESSAGEFAILWARN.icon(), + ProjectExplorer::Icons::DESKTOP_DEVICE.icon(), // for now }; // provide an icon for unknown?? if (result < 0 || result >= Result::MessageInternal) { @@ -74,6 +78,8 @@ static QIcon testResultIcon(Result::Type result) { return icons[16]; case Result::MessageTestCaseFailWarn: return icons[17]; + case Result::Application: + return icons[18]; default: return QIcon(); } @@ -224,7 +230,32 @@ void TestResultModel::addTestResult(const TestResultPtr &testResult, bool autoEx m_testResultCount[testResult->result()]++; TestResultItem *newItem = new TestResultItem(testResult); - TestResultItem *parentItem = findParentItemFor(newItem); + + TestResultItem *root = nullptr; + if (AutotestPlugin::settings()->displayApplication) { + const QString application = testResult->id(); + if (!application.isEmpty()) { + for (int row = rootItem()->childCount() - 1; row >= 0; --row) { + TestResultItem *tmp = static_cast(rootItem()->childAt(row)); + auto tmpTestResult = tmp->testResult(); + if (tmpTestResult->id() == application) { + root = tmp; + break; + } + } + if (!root) { + TestResult *tmpAppResult = new TestResult(application, application); + tmpAppResult->setResult(Result::Application); + root = new TestResultItem(TestResultPtr(tmpAppResult)); + if (lastRow >= 0) + rootItem()->insertChild(lastRow, root); + else + rootItem()->appendChild(root); + } + } + } + + TestResultItem *parentItem = findParentItemFor(newItem, root); addFileName(testResult->fileName()); // ensure we calculate the results pane correctly if (parentItem) { parentItem->appendChild(newItem); @@ -373,7 +404,7 @@ void TestResultFilterModel::enableAllResultTypes() << Result::MessageTestCaseSuccess << Result::MessageTestCaseSuccessWarn << Result::MessageTestCaseFail << Result::MessageTestCaseFailWarn << Result::MessageTestCaseEnd - << Result::MessageInfo << Result::MessageSystem; + << Result::MessageInfo << Result::MessageSystem << Result::Application; invalidateFilter(); } diff --git a/src/plugins/autotest/testsettings.cpp b/src/plugins/autotest/testsettings.cpp index c19ed8ecf4e..c825ea55733 100644 --- a/src/plugins/autotest/testsettings.cpp +++ b/src/plugins/autotest/testsettings.cpp @@ -42,6 +42,7 @@ static const char autoScrollKey[] = "AutoScrollResults"; static const char filterScanKey[] = "FilterScan"; static const char filtersKey[] = "WhiteListFilters"; static const char processArgsKey[] = "ProcessArgs"; +static const char displayApplicationKey[] = "DisplayApp"; static const char groupSuffix[] = ".group"; constexpr int defaultTimeout = 60000; @@ -60,6 +61,7 @@ void TestSettings::toSettings(QSettings *s) const s->setValue(limitResultOutputKey, limitResultOutput); s->setValue(autoScrollKey, autoScroll); s->setValue(processArgsKey, processArgs); + s->setValue(displayApplicationKey, displayApplication); s->setValue(filterScanKey, filterScan); s->setValue(filtersKey, whiteListFilters); // store frameworks and their current active and grouping state @@ -79,6 +81,7 @@ void TestSettings::fromSettings(QSettings *s) limitResultOutput = s->value(limitResultOutputKey, true).toBool(); autoScroll = s->value(autoScrollKey, true).toBool(); processArgs = s->value(processArgsKey, false).toBool(); + displayApplication = s->value(displayApplicationKey, false).toBool(); filterScan = s->value(filterScanKey, false).toBool(); whiteListFilters = s->value(filtersKey, QStringList()).toStringList(); // try to get settings for registered frameworks diff --git a/src/plugins/autotest/testsettings.h b/src/plugins/autotest/testsettings.h index 657ec4c0e27..6eff083e599 100644 --- a/src/plugins/autotest/testsettings.h +++ b/src/plugins/autotest/testsettings.h @@ -49,6 +49,7 @@ struct TestSettings bool autoScroll = true; bool filterScan = false; bool processArgs = false; + bool displayApplication = false; QHash frameworks; QHash frameworksGrouping; QStringList whiteListFilters; diff --git a/src/plugins/autotest/testsettingspage.cpp b/src/plugins/autotest/testsettingspage.cpp index 7c69be15106..e2bf15ae6c5 100644 --- a/src/plugins/autotest/testsettingspage.cpp +++ b/src/plugins/autotest/testsettingspage.cpp @@ -152,6 +152,7 @@ void TestSettingsWidget::setSettings(const TestSettings &settings) m_ui.limitResultOutputCB->setChecked(settings.limitResultOutput); m_ui.autoScrollCB->setChecked(settings.autoScroll); m_ui.processArgsCB->setChecked(settings.processArgs); + m_ui.displayAppCB->setChecked(settings.displayApplication); m_ui.filterGroupBox->setChecked(settings.filterScan); populateFrameworksListWidget(settings.frameworks); populateFiltersWidget(settings.whiteListFilters); @@ -166,6 +167,7 @@ TestSettings TestSettingsWidget::settings() const result.limitResultOutput = m_ui.limitResultOutputCB->isChecked(); result.autoScroll = m_ui.autoScrollCB->isChecked(); result.processArgs = m_ui.processArgsCB->isChecked(); + result.displayApplication = m_ui.displayAppCB->isChecked(); result.filterScan = m_ui.filterGroupBox->isChecked(); frameworkSettings(result); result.whiteListFilters = filters(); diff --git a/src/plugins/autotest/testsettingspage.ui b/src/plugins/autotest/testsettingspage.ui index bef08a5a285..dbdf49842a6 100644 --- a/src/plugins/autotest/testsettingspage.ui +++ b/src/plugins/autotest/testsettingspage.ui @@ -7,7 +7,7 @@ 0 0 585 - 431 + 458 @@ -73,6 +73,13 @@ + + + + Group results by application + + + From c5e43d86d12ce51c9035159a8acd86800fdf69bc Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 31 Jan 2019 13:16:44 +0100 Subject: [PATCH 08/16] Clang: Make diagnostic tooltips consistent Fix that triggering a diagnostic tooltip from the diagnostic location/range itself (underlined text) did not show the icon on the left and the actions/toolbuttons on the right in the tooltip. Instead of showing the tooltip content itself, request the tooltip for the corresponding text mark to get the extra decoration and actions. Change-Id: I5e94aca117a761f7a798d4f4b33db6e386e54d84 Reviewed-by: David Schulz Reviewed-by: Ivan Donchevskii --- .../clangcodemodel/clangdiagnosticmanager.cpp | 52 +++---------------- .../clangcodemodel/clangdiagnosticmanager.h | 3 +- .../clangeditordocumentprocessor.cpp | 28 +++------- .../clangeditordocumentprocessor.h | 4 +- .../clangcodemodel/clanghoverhandler.cpp | 42 +++++---------- src/plugins/clangcodemodel/clangtextmark.h | 2 + .../cpptools/baseeditordocumentprocessor.cpp | 9 ---- .../cpptools/baseeditordocumentprocessor.h | 2 - src/plugins/texteditor/texteditor.cpp | 7 +++ src/plugins/texteditor/texteditor.h | 5 ++ 10 files changed, 43 insertions(+), 111 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp b/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp index 72049242dc5..8bc0b925c29 100644 --- a/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp +++ b/src/plugins/clangcodemodel/clangdiagnosticmanager.cpp @@ -210,36 +210,6 @@ bool isDiagnosticAtLocation(const ClangBackEnd::DiagnosticContainer &diagnostic, return isDiagnosticRelatedToLocation(diagnostic, {cursorRange}, line, column); } -QVector -filteredDiagnosticsAtLocation(const QVector &diagnostics, - uint line, - uint column, - QTextDocument *textDocument) -{ - QVector filteredDiagnostics; - - foreach (const auto &diagnostic, diagnostics) { - if (isDiagnosticAtLocation(diagnostic, line, column, textDocument)) - filteredDiagnostics.append(diagnostic); - } - - return filteredDiagnostics; -} - -bool editorDocumentProcessorHasDiagnosticAt( - const QVector &diagnostics, - uint line, - uint column, - QTextDocument *textDocument) -{ - foreach (const auto &diagnostic, diagnostics) { - if (isDiagnosticAtLocation(diagnostic, line, column, textDocument)) - return true; - } - - return false; -} - QTextCursor cursorAtLastPositionOfLine(QTextDocument *textDocument, int lineNumber) { const QTextBlock textBlock = textDocument->findBlockByNumber(lineNumber - 1); @@ -399,24 +369,16 @@ TextEditor::RefactorMarkers ClangDiagnosticManager::takeFixItAvailableMarkers() return fixItAvailableMarkers; } -bool ClangDiagnosticManager::hasDiagnosticsAt(uint line, uint column) const +TextEditor::TextMarks ClangDiagnosticManager::diagnosticTextMarksAt(uint line, uint column) const { - QTextDocument *textDocument = m_textDocument->document(); + QList textMarks; - return editorDocumentProcessorHasDiagnosticAt(m_errorDiagnostics, line, column, textDocument) - || editorDocumentProcessorHasDiagnosticAt(m_warningDiagnostics, line, column, textDocument); -} + for (ClangTextMark *textMark : m_clangTextMarks) { + if (isDiagnosticAtLocation(textMark->diagnostic(), line, column, m_textDocument->document())) + textMarks << textMark; + } -QVector -ClangDiagnosticManager::diagnosticsAt(uint line, uint column) const -{ - QTextDocument *textDocument = m_textDocument->document(); - - QVector diagnostics; - diagnostics += filteredDiagnosticsAtLocation(m_errorDiagnostics, line, column, textDocument); - diagnostics += filteredDiagnosticsAtLocation(m_warningDiagnostics, line, column, textDocument); - - return diagnostics; + return textMarks; } void ClangDiagnosticManager::invalidateDiagnostics() diff --git a/src/plugins/clangcodemodel/clangdiagnosticmanager.h b/src/plugins/clangcodemodel/clangdiagnosticmanager.h index d0c31bf68bc..2996936ed08 100644 --- a/src/plugins/clangcodemodel/clangdiagnosticmanager.h +++ b/src/plugins/clangcodemodel/clangdiagnosticmanager.h @@ -57,8 +57,7 @@ public: QList takeExtraSelections(); TextEditor::RefactorMarkers takeFixItAvailableMarkers(); - bool hasDiagnosticsAt(uint line, uint column) const; - QVector diagnosticsAt(uint line, uint column) const; + QList diagnosticTextMarksAt(uint line, uint column) const; void invalidateDiagnostics(); void clearDiagnosticsWithFixIts(); diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 8e1d06da6c6..40d7e4e63fe 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -48,7 +48,6 @@ #include #include -#include #include #include #include @@ -292,27 +291,6 @@ TextEditor::QuickFixOperations ClangEditorDocumentProcessor::extraRefactoringOpe return extractor.extract(assistInterface.fileName(), currentLine(assistInterface)); } -bool ClangEditorDocumentProcessor::hasDiagnosticsAt(uint line, uint column) const -{ - return m_diagnosticManager.hasDiagnosticsAt(line, column); -} - -void ClangEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint line, - uint column, - QLayout *target) const -{ - using Internal::ClangDiagnosticWidget; - - const QVector diagnostics - = m_diagnosticManager.diagnosticsAt(line, column); - - target->addWidget( - ClangDiagnosticWidget::createWidget(diagnostics, ClangDiagnosticWidget::ToolTip)); - auto link = TextEditor::DisplaySettings::createAnnotationSettingsLink(); - target->addWidget(link); - target->setAlignment(link, Qt::AlignRight); -} - void ClangEditorDocumentProcessor::editorDocumentTimerRestarted() { m_updateBackendDocumentTimer.stop(); // Wait for the next call to run(). @@ -323,6 +301,12 @@ void ClangEditorDocumentProcessor::invalidateDiagnostics() m_diagnosticManager.invalidateDiagnostics(); } +TextEditor::TextMarks ClangEditorDocumentProcessor::diagnosticTextMarksAt(uint line, + uint column) const +{ + return m_diagnosticManager.diagnosticTextMarksAt(line, column); +} + void ClangEditorDocumentProcessor::setParserConfig( const CppTools::BaseEditorDocumentParser::Configuration &config) { diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h index a7da1bb2e1c..8e0ee003d30 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.h +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.h @@ -83,8 +83,8 @@ public: extraRefactoringOperations(const TextEditor::AssistInterface &assistInterface) override; void invalidateDiagnostics() override; - bool hasDiagnosticsAt(uint line, uint column) const override; - void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *target) const override; + + TextEditor::TextMarks diagnosticTextMarksAt(uint line, uint column) const; void editorDocumentTimerRestarted() override; diff --git a/src/plugins/clangcodemodel/clanghoverhandler.cpp b/src/plugins/clangcodemodel/clanghoverhandler.cpp index da9f974adb6..58f414d9f11 100644 --- a/src/plugins/clangcodemodel/clanghoverhandler.cpp +++ b/src/plugins/clangcodemodel/clanghoverhandler.cpp @@ -25,8 +25,9 @@ #include "clanghoverhandler.h" +#include "clangeditordocumentprocessor.h" + #include -#include #include #include #include @@ -61,32 +62,17 @@ static CppTools::BaseEditorDocumentProcessor *editorDocumentProcessor(TextEditor return nullptr; } -static bool editorDocumentProcessorHasDiagnosticAt(TextEditorWidget *editorWidget, int pos) +static TextMarks diagnosticTextMarksAt(TextEditorWidget *editorWidget, int position) { - if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { - int line, column; - if (Utils::Text::convertPosition(editorWidget->document(), pos, &line, &column)) - return processor->hasDiagnosticsAt(line, column); - } + const auto processor = qobject_cast( + editorDocumentProcessor(editorWidget)); + QTC_ASSERT(processor, return TextMarks()); - return false; -} + int line, column; + const bool ok = Utils::Text::convertPosition(editorWidget->document(), position, &line, &column); + QTC_ASSERT(ok, return TextMarks()); -static void processWithEditorDocumentProcessor(TextEditorWidget *editorWidget, - const QPoint &point, - int position, - const Core::HelpItem &helpItem) -{ - if (CppTools::BaseEditorDocumentProcessor *processor = editorDocumentProcessor(editorWidget)) { - int line, column; - if (Utils::Text::convertPosition(editorWidget->document(), position, &line, &column)) { - auto layout = new QVBoxLayout; - layout->setContentsMargins(0, 0, 0, 0); - layout->setSpacing(2); - processor->addDiagnosticToolTipToLayout(line, column, layout); - Utils::ToolTip::show(point, layout, editorWidget, qVariantFromValue(helpItem)); - } - } + return processor->diagnosticTextMarksAt(line, column); } static QFuture editorDocumentHandlesToolTipInfo( @@ -189,7 +175,7 @@ void ClangHoverHandler::identifyMatch(TextEditorWidget *editorWidget, m_cursorPosition = -1; // Check for diagnostics (sync) - if (!isContextHelpRequest() && editorDocumentProcessorHasDiagnosticAt(editorWidget, pos)) { + if (!isContextHelpRequest() && !diagnosticTextMarksAt(editorWidget, pos).isEmpty()) { qCDebug(hoverLog) << "Checking for diagnostic at" << pos; setPriority(Priority_Diagnostic); m_cursorPosition = pos; @@ -275,10 +261,8 @@ void ClangHoverHandler::operateTooltip(TextEditor::TextEditorWidget *editorWidge const QPoint &point) { if (priority() == Priority_Diagnostic) { - processWithEditorDocumentProcessor(editorWidget, - point, - m_cursorPosition, - lastHelpItemIdentified()); + const TextMarks textMarks = diagnosticTextMarksAt(editorWidget, m_cursorPosition); + editorWidget->showTextMarksToolTip(point, textMarks); return; } diff --git a/src/plugins/clangcodemodel/clangtextmark.h b/src/plugins/clangcodemodel/clangtextmark.h index 1301cd200b7..00cadfb5c82 100644 --- a/src/plugins/clangcodemodel/clangtextmark.h +++ b/src/plugins/clangcodemodel/clangtextmark.h @@ -44,7 +44,9 @@ public: const RemovedFromEditorHandler &removedHandler, bool fullVisualization); + ClangBackEnd::DiagnosticContainer diagnostic() const { return m_diagnostic; } void updateIcon(bool valid = true); + private: bool addToolTipContent(QLayout *target) const override; void removedFromEditor() override; diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.cpp b/src/plugins/cpptools/baseeditordocumentprocessor.cpp index 8c869ee51f7..6bd91fc5640 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.cpp +++ b/src/plugins/cpptools/baseeditordocumentprocessor.cpp @@ -72,15 +72,6 @@ BaseEditorDocumentProcessor::extraRefactoringOperations(const TextEditor::Assist return TextEditor::QuickFixOperations(); } -bool BaseEditorDocumentProcessor::hasDiagnosticsAt(uint, uint) const -{ - return false; -} - -void BaseEditorDocumentProcessor::addDiagnosticToolTipToLayout(uint, uint, QLayout *) const -{ -} - void BaseEditorDocumentProcessor::editorDocumentTimerRestarted() { } diff --git a/src/plugins/cpptools/baseeditordocumentprocessor.h b/src/plugins/cpptools/baseeditordocumentprocessor.h index efdb29a9f8f..cf08f7b5c40 100644 --- a/src/plugins/cpptools/baseeditordocumentprocessor.h +++ b/src/plugins/cpptools/baseeditordocumentprocessor.h @@ -81,8 +81,6 @@ public: extraRefactoringOperations(const TextEditor::AssistInterface &assistInterface); virtual void invalidateDiagnostics(); - virtual bool hasDiagnosticsAt(uint line, uint column) const; - virtual void addDiagnosticToolTipToLayout(uint line, uint column, QLayout *layout) const; virtual void editorDocumentTimerRestarted(); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index acf9072bc25..977c224dcef 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -3555,6 +3555,13 @@ QPoint TextEditorWidget::toolTipPosition(const QTextCursor &c) const return cursorPos + QPoint(d->m_extraArea->width(), HostOsInfo::isWindowsHost() ? -24 : -16); } +void TextEditorWidget::showTextMarksToolTip(const QPoint &pos, + const TextMarks &marks, + const TextMark *mainTextMark) const +{ + d->showTextMarksToolTip(pos, marks, mainTextMark); +} + void TextEditorWidgetPrivate::processTooltipRequest(const QTextCursor &c) { const QPoint toolTipPoint = q->toolTipPosition(c); diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index 4eaae7b5bb8..5cf1ecbd1a3 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -59,6 +59,7 @@ class HighlightScrollBarController; namespace TextEditor { class TextDocument; +class TextMark; class BaseHoverHandler; class RefactorOverlay; struct RefactorMarker; @@ -68,6 +69,7 @@ class IAssistProvider; class ICodeStylePreferences; class CompletionAssistProvider; using RefactorMarkers = QList; +using TextMarks = QList; namespace Internal { class BaseTextEditorPrivate; @@ -274,6 +276,9 @@ public: QRegion translatedLineRegion(int lineStart, int lineEnd) const; QPoint toolTipPosition(const QTextCursor &c) const; + void showTextMarksToolTip(const QPoint &pos, + const TextMarks &marks, + const TextMark *mainTextMark = nullptr) const; void invokeAssist(AssistKind assistKind, IAssistProvider *provider = nullptr); From 719749103a17a6c89cec86bda943232f23e5ee86 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Tue, 5 Feb 2019 11:16:09 +0100 Subject: [PATCH 09/16] Clang: Remove some pointless "this" capture Change-Id: I8ac56d0ec34128aa33263f171483c36dae608d01 Reviewed-by: Ivan Donchevskii --- src/plugins/cpptools/clangdiagnosticconfigswidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp index 1a3031db8a0..22e7a93b8f9 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp @@ -536,7 +536,7 @@ public: const auto *node = ClazyChecksTree::fromIndex(index); if (node->kind == ClazyChecksTree::CheckNode) { const QStringList topics = node->checkInfo.topics; - return Utils::anyOf(m_topics, [this, topics](const QString &topic) { + return Utils::anyOf(m_topics, [topics](const QString &topic) { return topics.contains(topic); }); } From 69565d6c88ad66e11817bd661c20af8395b6000e Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 1 Feb 2019 16:50:29 +0100 Subject: [PATCH 10/16] QmakePM: Respect editor settings when adding files to project If the user wants to indent with tabs, then consider that when adding source files via the UI. But try not to mix: If the respective variable already uses a different indentation consistently, then keep using that one. Fixes: QTCREATORBUG-8016 Change-Id: I037c9ac4d4e7fbbe5753a846e57d938bbb440d6a Reviewed-by: David Schulz --- .../qmakeprojectmanager/qmakeparsernodes.cpp | 25 +++++- .../qmakeprojectmanager/qmakeparsernodes.h | 2 + src/shared/proparser/prowriter.cpp | 65 ++++++++++---- src/shared/proparser/prowriter.h | 5 +- .../auto/profilewriter/tst_profilewriter.cpp | 88 +++++++++---------- 5 files changed, 120 insertions(+), 65 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp index 21d5627f0f0..c0034972d65 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.cpp @@ -36,10 +36,14 @@ #include #include #include +#include #include #include #include #include +#include +#include +#include #include #include @@ -378,6 +382,19 @@ void QmakePriFile::watchFolders(const QSet &folders) m_watchedFolders = folderStrings; } +QString QmakePriFile::continuationIndent() const +{ + const EditorConfiguration *editorConf = project()->editorConfiguration(); + const TextEditor::TabSettings &tabSettings = editorConf->useGlobalSettings() + ? TextEditor::TextEditorSettings::codeStyle()->tabSettings() + : editorConf->codeStyle()->tabSettings(); + if (tabSettings.m_continuationAlignBehavior == TextEditor::TabSettings::ContinuationAlignWithIndent + && tabSettings.m_tabPolicy == TextEditor::TabSettings::TabsOnlyTabPolicy) { + return QString("\t"); + } + return QString(tabSettings.m_indentSize, ' '); +} + bool QmakePriFile::knowsFile(const FileName &filePath) const { return m_recursiveEnumerateFiles.contains(filePath); @@ -747,7 +764,8 @@ bool QmakePriFile::renameFile(const QString &oldName, ProWriter::addFiles(includeFile, &lines, QStringList(newName), - varNameForAdding(mimeType)); + varNameForAdding(mimeType), + continuationIndent()); if (mode == Change::Save) save(lines); includeFile->deref(); @@ -777,7 +795,8 @@ void QmakePriFile::changeFiles(const QString &mimeType, if (change == AddToProFile) { // Use the first variable for adding. - ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType)); + ProWriter::addFiles(includeFile, &lines, filePaths, varNameForAdding(mimeType), + continuationIndent()); notChanged->clear(); } else { // RemoveFromProFile QDir priFileDir = QDir(m_qmakeProFile->directoryPath().toString()); @@ -818,7 +837,7 @@ bool QmakePriFile::setProVariable(const QString &var, const QStringList &values, ProWriter::putVarValues(includeFile, &lines, values, var, ProWriter::PutFlags(flags), - scope); + scope, continuationIndent()); save(lines); includeFile->deref(); diff --git a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h index f2bb612b7e1..6f0e13a5c95 100644 --- a/src/plugins/qmakeprojectmanager/qmakeparsernodes.h +++ b/src/plugins/qmakeprojectmanager/qmakeparsernodes.h @@ -216,6 +216,8 @@ private: static void processValues(Internal::QmakePriFileEvalResult &result); void watchFolders(const QSet &folders); + QString continuationIndent() const; + QmakeProject *m_project = nullptr; QmakeProFile *m_qmakeProFile = nullptr; QmakePriFile *m_parent = nullptr; diff --git a/src/shared/proparser/prowriter.cpp b/src/shared/proparser/prowriter.cpp index 98547f89edb..3ca7220621d 100644 --- a/src/shared/proparser/prowriter.cpp +++ b/src/shared/proparser/prowriter.cpp @@ -246,6 +246,7 @@ bool ProWriter::locateVarValues(const ushort *tokPtr, const ushort *tokPtrEnd, struct LineInfo { + QString indent; int continuationPos = 0; bool hasComment = false; }; @@ -260,14 +261,29 @@ static LineInfo lineInfo(const QString &line) li.continuationPos = idx; for (int i = idx - 1; i >= 0 && (line.at(i) == ' ' || line.at(i) == '\t'); --i) --li.continuationPos; + for (int i = 0; i < line.length() && (line.at(i) == ' ' || line.at(i) == '\t'); ++i) + li.indent += line.at(i); return li; } -static int skipContLines(QStringList *lines, int lineNo, bool addCont) +struct ContinuationInfo { + QString indent; // Empty means use default + int lineNo; +}; + +static ContinuationInfo skipContLines(QStringList *lines, int lineNo, bool addCont) { + bool hasConsistentIndent = true; + QString lastIndent; for (; lineNo < lines->count(); lineNo++) { const QString line = lines->at(lineNo); LineInfo li = lineInfo(line); + if (hasConsistentIndent) { + if (lastIndent.isEmpty()) + lastIndent = li.indent; + else if (lastIndent != li.indent) + hasConsistentIndent = false; + } if (li.continuationPos == 0) { if (li.hasComment) continue; @@ -280,34 +296,45 @@ static int skipContLines(QStringList *lines, int lineNo, bool addCont) break; } } - return lineNo; + ContinuationInfo ci; + if (hasConsistentIndent) + ci.indent = lastIndent; + ci.lineNo = lineNo; + return ci; } -void ProWriter::putVarValues(ProFile *profile, QStringList *lines, - const QStringList &values, const QString &var, PutFlags flags, const QString &scope) +void ProWriter::putVarValues(ProFile *profile, QStringList *lines, const QStringList &values, + const QString &var, PutFlags flags, const QString &scope, + const QString &continuationIndent) { - QString indent = scope.isEmpty() ? QString() : QLatin1String(" "); + QString indent = scope.isEmpty() ? QString() : continuationIndent; + const auto effectiveContIndent = [indent, continuationIndent](const ContinuationInfo &ci) { + return !ci.indent.isEmpty() ? ci.indent : continuationIndent + indent; + }; int scopeStart = -1, lineNo; if (locateVarValues(profile->tokPtr(), profile->tokPtrEnd(), scope, var, &scopeStart, &lineNo)) { if (flags & ReplaceValues) { // remove continuation lines with old values - int lNo = skipContLines(lines, lineNo, false); - lines->erase(lines->begin() + lineNo + 1, lines->begin() + lNo); + const ContinuationInfo contInfo = skipContLines(lines, lineNo, false); + lines->erase(lines->begin() + lineNo + 1, lines->begin() + contInfo.lineNo); // remove rest of the line QString &line = (*lines)[lineNo]; int eqs = line.indexOf(QLatin1Char('=')); if (eqs >= 0) // If this is not true, we mess up the file a bit. line.truncate(eqs + 1); // put new values - foreach (const QString &v, values) - line += ((flags & MultiLine) ? QLatin1String(" \\\n ") + indent : QString::fromLatin1(" ")) + v; + foreach (const QString &v, values) { + line += ((flags & MultiLine) ? QLatin1String(" \\\n") + effectiveContIndent(contInfo) + : QString::fromLatin1(" ")) + v; + } } else { - int endLineNo = skipContLines(lines, lineNo, false); + const ContinuationInfo contInfo = skipContLines(lines, lineNo, false); + int endLineNo = contInfo.lineNo; for (const QString &v : values) { int curLineNo = lineNo + 1; while (curLineNo < endLineNo && v >= lines->at(curLineNo).trimmed()) ++curLineNo; - QString newLine = " " + indent + v; + QString newLine = effectiveContIndent(contInfo) + v; if (curLineNo == endLineNo) { QString &oldLastLine = (*lines)[endLineNo - 1]; oldLastLine.insert(lineInfo(oldLastLine).continuationPos, " \\"); @@ -322,6 +349,7 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines, // Create & append new variable item QString added; int lNo = lines->count(); + ContinuationInfo contInfo; if (!scope.isEmpty()) { if (scopeStart < 0) { added = QLatin1Char('\n') + scope + QLatin1String(" {"); @@ -329,8 +357,10 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines, QRegExp rx(QLatin1String("(\\s*") + scope + QLatin1String("\\s*:\\s*)[^\\s{].*")); if (rx.exactMatch(lines->at(scopeStart))) { (*lines)[scopeStart].replace(0, rx.cap(1).length(), - QString(scope + QLatin1String(" {\n "))); - lNo = skipContLines(lines, scopeStart, false); + QString(scope + QLatin1String(" {\n") + + continuationIndent)); + contInfo = skipContLines(lines, scopeStart, false); + lNo = contInfo.lineNo; scopeStart = -1; } } @@ -357,14 +387,16 @@ void ProWriter::putVarValues(ProFile *profile, QStringList *lines, added += QLatin1Char('\n'); added += indent + var + QLatin1String((flags & AppendOperator) ? " +=" : " ="); foreach (const QString &v, values) - added += ((flags & MultiLine) ? QLatin1String(" \\\n ") + indent : QString::fromLatin1(" ")) + v; + added += ((flags & MultiLine) ? QLatin1String(" \\\n") + effectiveContIndent(contInfo) + : QString::fromLatin1(" ")) + v; if (!scope.isEmpty() && scopeStart < 0) added += QLatin1String("\n}"); lines->insert(lNo, added); } } -void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList &values, const QString &var) +void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList &values, + const QString &var, const QString &continuationIndent) { QStringList valuesToWrite; QString prefixPwd; @@ -374,7 +406,8 @@ void ProWriter::addFiles(ProFile *profile, QStringList *lines, const QStringList foreach (const QString &v, values) valuesToWrite << (prefixPwd + baseDir.relativeFilePath(v)); - putVarValues(profile, lines, valuesToWrite, var, AppendValues | MultiLine | AppendOperator); + putVarValues(profile, lines, valuesToWrite, var, AppendValues | MultiLine | AppendOperator, + QString(), continuationIndent); } static void findProVariables(const ushort *tokPtr, const QStringList &vars, diff --git a/src/shared/proparser/prowriter.h b/src/shared/proparser/prowriter.h index 808884837b3..7d3dca765d9 100644 --- a/src/shared/proparser/prowriter.h +++ b/src/shared/proparser/prowriter.h @@ -51,11 +51,12 @@ public: static void putVarValues(ProFile *profile, QStringList *lines, const QStringList &values, const QString &var, PutFlags flags, - const QString &scope = QString()); + const QString &scope, const QString &continuationIndent); static QList removeVarValues(ProFile *profile, QStringList *lines, const QStringList &values, const QStringList &vars); - static void addFiles(ProFile *profile, QStringList *lines, const QStringList &filePaths, const QString &var); + static void addFiles(ProFile *profile, QStringList *lines, const QStringList &filePaths, + const QString &var, const QString &continuationIndent); static QStringList removeFiles(ProFile *profile, QStringList *lines, const QDir &proFileDir, const QStringList &filePaths, const QStringList &vars); diff --git a/tests/auto/profilewriter/tst_profilewriter.cpp b/tests/auto/profilewriter/tst_profilewriter.cpp index b820d6fdcf0..2abc7ccaa25 100644 --- a/tests/auto/profilewriter/tst_profilewriter.cpp +++ b/tests/auto/profilewriter/tst_profilewriter.cpp @@ -102,7 +102,7 @@ void tst_ProFileWriter::adds_data() "add new append multi", f_foo, 0, "", "SOURCES += \\\n" - " foo" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, @@ -111,7 +111,7 @@ void tst_ProFileWriter::adds_data() "# test file\n" "\n" "SOURCES += \\\n" - " foo" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, @@ -120,7 +120,7 @@ void tst_ProFileWriter::adds_data() "\n" "\n", "SOURCES += \\\n" - " foo\n" + "\tfoo\n" "\n" "\n" "\n" @@ -135,7 +135,7 @@ void tst_ProFileWriter::adds_data() "# test file\n" "\n" "SOURCES += \\\n" - " foo\n" + "\tfoo\n" "\n" "\n" "\n" @@ -147,7 +147,7 @@ void tst_ProFileWriter::adds_data() "# test file\n" "\n" "SOURCES = \\\n" - " foo" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::OneLine, @@ -184,43 +184,43 @@ void tst_ProFileWriter::adds_data() "unix:SOURCES = some files\n" "\n" "SOURCES += \\\n" - " foo" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, "add new after some scope", f_foo, 0, "unix {\n" - " SOMEVAR = foo\n" + "\tSOMEVAR = foo\n" "}", "unix {\n" - " SOMEVAR = foo\n" + "\tSOMEVAR = foo\n" "}\n" "\n" "SOURCES += \\\n" - " foo" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, "add to existing (wrong operator)", f_foo, 0, "SOURCES = some files", "SOURCES = some files \\\n" - " foo" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, "insert at end", f_foo_bar, 0, "SOURCES = some files", "SOURCES = some files \\\n" - " bar \\\n" - " foo" + "\tbar \\\n" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, "insert into empty", f_foo_bar, 0, "SOURCES =", "SOURCES = \\\n" - " bar \\\n" - " foo" + "\tbar \\\n" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, @@ -239,33 +239,33 @@ void tst_ProFileWriter::adds_data() "add to existing after comment (wrong operator)", f_foo, 0, "SOURCES = some files # comment", "SOURCES = some files \\ # comment\n" - " foo" + "\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, "add to existing after comment line (wrong operator)", f_foo, 0, "SOURCES = some \\\n" " # comment\n" - " files", + "\tfiles", "SOURCES = some \\\n" " # comment\n" - " files \\\n" - " foo" + "\tfiles \\\n" + "\tfoo" }, { PW::AppendValues|PW::AssignOperator|PW::MultiLine, "add to existing", f_foo, 0, "SOURCES = some files", "SOURCES = some files \\\n" - " foo" + "\tfoo" }, { PW::ReplaceValues|PW::AssignOperator|PW::MultiLine, "replace existing multi", f_foo_bar, 0, "SOURCES = some files", "SOURCES = \\\n" - " foo \\\n" - " bar" + "\tfoo \\\n" + "\tbar" }, { PW::ReplaceValues|PW::AssignOperator|PW::OneLine, @@ -278,7 +278,7 @@ void tst_ProFileWriter::adds_data() "replace existing complex last", f_foo_bar, 0, "SOURCES = some \\\n" " # comment\n" - " files", + "\tfiles", "SOURCES = foo bar" }, { @@ -286,7 +286,7 @@ void tst_ProFileWriter::adds_data() "replace existing complex middle 1", f_foo_bar, 0, "SOURCES = some \\\n" " # comment\n" - " files\n" + "\tfiles\n" "HEADERS = blubb", "SOURCES = foo bar\n" "HEADERS = blubb" @@ -296,7 +296,7 @@ void tst_ProFileWriter::adds_data() "replace existing complex middle 2", f_foo_bar, 0, "SOURCES = some \\\n" " # comment\n" - " files\n" + "\tfiles\n" "\n" "HEADERS = blubb", "SOURCES = foo bar\n" @@ -308,7 +308,7 @@ void tst_ProFileWriter::adds_data() "replace existing complex middle 3", f_foo_bar, 0, "SOURCES = some \\\n" " # comment\n" - " files \\\n" + "\tfiles \\\n" "\n" "HEADERS = blubb", "SOURCES = foo bar\n" @@ -324,7 +324,7 @@ void tst_ProFileWriter::adds_data() "SOURCES = yo\n" "\n" "dog {\n" - " SOURCES += foo\n" + "\tSOURCES += foo\n" "}" }, { @@ -332,13 +332,13 @@ void tst_ProFileWriter::adds_data() "scoped new / extend scope", f_foo, "dog", "# test file\n" "dog {\n" - " HEADERS += yo\n" + "\tHEADERS += yo\n" "}", "# test file\n" "dog {\n" - " HEADERS += yo\n" + "\tHEADERS += yo\n" "\n" - " SOURCES += foo\n" + "\tSOURCES += foo\n" "}" }, { @@ -356,7 +356,7 @@ void tst_ProFileWriter::adds_data() " yo \\\n" " blubb\n" "\n" - " SOURCES += foo\n" + "\tSOURCES += foo\n" "}" }, { @@ -367,7 +367,7 @@ void tst_ProFileWriter::adds_data() "}", "# test file\n" "dog {\n" - " SOURCES += foo\n" + "\tSOURCES += foo\n" "}" }, { @@ -377,9 +377,9 @@ void tst_ProFileWriter::adds_data() "dog:HEADERS += yo", "# test file\n" "dog {\n" - " HEADERS += yo\n" + "\tHEADERS += yo\n" "\n" - " SOURCES += foo\n" + "\tSOURCES += foo\n" "}" }, { @@ -392,10 +392,10 @@ void tst_ProFileWriter::adds_data() "blubb()", "# test file\n" "dog {\n" - " HEADERS += yo \\\n" + "\tHEADERS += yo \\\n" " you\n" "\n" - " SOURCES += foo\n" + "\tSOURCES += foo\n" "}\n" "\n" "blubb()" @@ -413,8 +413,8 @@ void tst_ProFileWriter::adds_data() " SOMEVAR = foo\n" " }\n" "\n" - " SOURCES += \\\n" - " foo\n" + "\tSOURCES += \\\n" + "\t\tfoo\n" "}" }, { @@ -425,7 +425,7 @@ void tst_ProFileWriter::adds_data() "}", "# test file\n" "dog: {\n" - " SOURCES += foo\n" + "\tSOURCES += foo\n" "}" }, { @@ -435,7 +435,7 @@ void tst_ProFileWriter::adds_data() "dog:SOURCES = yo", "# test file\n" "dog:SOURCES = yo \\\n" - " foo" + "\t\tfoo" }, { PW::AppendValues|PW::AppendOperator|PW::MultiLine, @@ -446,8 +446,8 @@ void tst_ProFileWriter::adds_data() "animal:!dog:SOURCES = yo\n" "\n" "dog {\n" - " SOURCES += \\\n" - " foo\n" + "\tSOURCES += \\\n" + "\t\tfoo\n" "}" }, }; @@ -478,7 +478,7 @@ void tst_ProFileWriter::adds() QMakeParser parser(0, &vfs, &parseHandler); ProFile *proFile = parser.parsedProBlock(QStringRef(&input), 0, QLatin1String(BASE_DIR "/test.pro"), 1); QVERIFY(proFile); - PW::putVarValues(proFile, &lines, values, var, PW::PutFlags(flags), scope); + PW::putVarValues(proFile, &lines, values, var, PW::PutFlags(flags), scope, "\t"); proFile->deref(); QCOMPARE(lines.join(QLatin1Char('\n')), output); @@ -692,7 +692,7 @@ void tst_ProFileWriter::addFiles() QStringList lines = input.split(QLatin1Char('\n')); QString output = QLatin1String( "SOURCES = foo.cpp \\\n" - " sub/bar.cpp" + "\tsub/bar.cpp" ); QMakeVfs vfs; @@ -701,7 +701,7 @@ void tst_ProFileWriter::addFiles() QVERIFY(proFile); QmakeProjectManager::Internal::ProWriter::addFiles(proFile, &lines, QStringList() << QString::fromLatin1(BASE_DIR "/sub/bar.cpp"), - QLatin1String("SOURCES")); + QLatin1String("SOURCES"), "\t"); proFile->deref(); QCOMPARE(lines.join(QLatin1Char('\n')), output); From b9d3055e7218e6dc202047c4a341df51c8e8cd67 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 31 Jan 2019 10:16:28 +0100 Subject: [PATCH 11/16] Clang: Allow to forward warnings flags from build system Change-Id: I47ebb1ce4f3b5544408eb1d0f891ed5090394282 Reviewed-by: Leena Miettinen Reviewed-by: Ivan Donchevskii --- .../clangeditordocumentprocessor.cpp | 16 ++++++-- src/plugins/clangcodemodel/clangutils.cpp | 11 +++-- src/plugins/clangcodemodel/clangutils.h | 2 + .../clangtools/clangtoolruncontrol.cpp | 1 + src/plugins/cpptools/clangbasechecks.ui | 7 ++++ .../cpptools/clangdiagnosticconfig.cpp | 13 +++++- src/plugins/cpptools/clangdiagnosticconfig.h | 4 ++ .../cpptools/clangdiagnosticconfigsmodel.cpp | 13 ++++++ .../cpptools/clangdiagnosticconfigswidget.cpp | 40 +++++++++++++------ .../cpptools/clangdiagnosticconfigswidget.h | 6 +-- .../cpptools/compileroptionsbuilder.cpp | 9 +++-- src/plugins/cpptools/compileroptionsbuilder.h | 16 +++++--- .../unittest/compileroptionsbuilder-test.cpp | 26 ++++++++++++ 13 files changed, 132 insertions(+), 32 deletions(-) diff --git a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 40d7e4e63fe..aaca6380d2e 100644 --- a/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp +++ b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp @@ -452,6 +452,10 @@ public: const QStringList &options() const { return m_options; } const Core::Id &diagnosticConfigId() const { return m_diagnosticConfigId; } + CppTools::UseBuildSystemWarnings useBuildSystemWarnings() const + { + return m_useBuildSystemWarnings; + } private: void addLanguageOptions() @@ -491,6 +495,9 @@ private: void addDiagnosticOptionsForConfig(const CppTools::ClangDiagnosticConfig &diagnosticConfig) { m_diagnosticConfigId = diagnosticConfig.id(); + m_useBuildSystemWarnings = diagnosticConfig.useBuildSystemWarnings() + ? CppTools::UseBuildSystemWarnings::Yes + : CppTools::UseBuildSystemWarnings::No; m_options.append(diagnosticConfig.clangOptions()); addClangTidyOptions(diagnosticConfig); @@ -565,6 +572,7 @@ private: const CppTools::ProjectPart &m_projectPart; Core::Id m_diagnosticConfigId; + CppTools::UseBuildSystemWarnings m_useBuildSystemWarnings = CppTools::UseBuildSystemWarnings::No; CppTools::CompilerOptionsBuilder m_builder; QStringList m_options; }; @@ -586,13 +594,13 @@ void ClangEditorDocumentProcessor::updateBackendDocument(CppTools::ProjectPart & return; } - const QStringList projectPartOptions = ClangCodeModel::Utils::createClangOptions( - projectPart, - CppTools::ProjectFile::Unsupported); // No language option as FileOptionsBuilder adds it. - const FileOptionsBuilder fileOptions(filePath(), projectPart); m_diagnosticConfigId = fileOptions.diagnosticConfigId(); + const QStringList projectPartOptions = ClangCodeModel::Utils::createClangOptions( + projectPart, fileOptions.useBuildSystemWarnings(), + CppTools::ProjectFile::Unsupported); // No language option as FileOptionsBuilder adds it. + const QStringList compilationArguments = projectPartOptions + fileOptions.options(); m_communicator.documentsOpened( diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 4741f1ef96a..8a27a115a2d 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -66,11 +66,13 @@ namespace Utils { class LibClangOptionsBuilder final : public CompilerOptionsBuilder { public: - LibClangOptionsBuilder(const ProjectPart &projectPart) + LibClangOptionsBuilder(const ProjectPart &projectPart, + UseBuildSystemWarnings useBuildSystemWarnings) : CompilerOptionsBuilder(projectPart, UseSystemHeader::No, UseTweakedHeaderPaths::Yes, UseLanguageDefines::No, + useBuildSystemWarnings, QString(CLANG_VERSION), QString(CLANG_RESOURCE_DIR)) { @@ -101,9 +103,12 @@ private: } }; -QStringList createClangOptions(const ProjectPart &projectPart, ProjectFile::Kind fileKind) +QStringList createClangOptions(const ProjectPart &projectPart, + UseBuildSystemWarnings useBuildSystemWarnings, + ProjectFile::Kind fileKind) { - return LibClangOptionsBuilder(projectPart).build(fileKind, UsePrecompiledHeaders::No); + return LibClangOptionsBuilder(projectPart, useBuildSystemWarnings) + .build(fileKind, UsePrecompiledHeaders::No); } ProjectPart::Ptr projectPartForFile(const QString &filePath) diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index 0a7a1127bf9..b7f705b57b8 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -28,6 +28,7 @@ #include #include +#include #include @@ -53,6 +54,7 @@ CppTools::CppEditorDocumentHandle *cppDocument(const QString &filePath); void setLastSentDocumentRevision(const QString &filePath, uint revision); QStringList createClangOptions(const CppTools::ProjectPart &projectPart, + CppTools::UseBuildSystemWarnings useBuildSystemWarnings, CppTools::ProjectFile::Kind fileKind); CppTools::ProjectPart::Ptr projectPartForFile(const QString &filePath); diff --git a/src/plugins/clangtools/clangtoolruncontrol.cpp b/src/plugins/clangtools/clangtoolruncontrol.cpp index a25d3fc9103..c4ca8a4abbc 100644 --- a/src/plugins/clangtools/clangtoolruncontrol.cpp +++ b/src/plugins/clangtools/clangtoolruncontrol.cpp @@ -195,6 +195,7 @@ static AnalyzeUnits toAnalyzeUnits(const FileInfos &fileInfos) UseSystemHeader::No, UseTweakedHeaderPaths::Yes, UseLanguageDefines::No, + UseBuildSystemWarnings::No, QString(CLANG_VERSION), QString(CLANG_RESOURCE_DIR)); QStringList arguments = extraClangToolsPrependOptions(); diff --git a/src/plugins/cpptools/clangbasechecks.ui b/src/plugins/cpptools/clangbasechecks.ui index 8455db10fb5..5092af67d3d 100644 --- a/src/plugins/cpptools/clangbasechecks.ui +++ b/src/plugins/cpptools/clangbasechecks.ui @@ -24,6 +24,13 @@ + + + + Use diagnostic flags from build system + + + diff --git a/src/plugins/cpptools/clangdiagnosticconfig.cpp b/src/plugins/cpptools/clangdiagnosticconfig.cpp index a340e8347c6..b254250e420 100644 --- a/src/plugins/cpptools/clangdiagnosticconfig.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfig.cpp @@ -75,7 +75,8 @@ bool ClangDiagnosticConfig::operator==(const ClangDiagnosticConfig &other) const && m_clangTidyMode == other.m_clangTidyMode && m_clangTidyChecks == other.m_clangTidyChecks && m_clazyChecks == other.m_clazyChecks - && m_isReadOnly == other.m_isReadOnly; + && m_isReadOnly == other.m_isReadOnly + && m_useBuildSystemWarnings == other.m_useBuildSystemWarnings; } bool ClangDiagnosticConfig::operator!=(const ClangDiagnosticConfig &other) const @@ -83,6 +84,16 @@ bool ClangDiagnosticConfig::operator!=(const ClangDiagnosticConfig &other) const return !(*this == other); } +bool ClangDiagnosticConfig::useBuildSystemWarnings() const +{ + return m_useBuildSystemWarnings; +} + +void ClangDiagnosticConfig::setUseBuildSystemWarnings(bool useBuildSystemWarnings) +{ + m_useBuildSystemWarnings = useBuildSystemWarnings; +} + ClangDiagnosticConfig::TidyMode ClangDiagnosticConfig::clangTidyMode() const { return m_clangTidyMode; diff --git a/src/plugins/cpptools/clangdiagnosticconfig.h b/src/plugins/cpptools/clangdiagnosticconfig.h index faaf439ad3d..bb3af15e0e1 100644 --- a/src/plugins/cpptools/clangdiagnosticconfig.h +++ b/src/plugins/cpptools/clangdiagnosticconfig.h @@ -65,6 +65,9 @@ public: bool isReadOnly() const; void setIsReadOnly(bool isReadOnly); + bool useBuildSystemWarnings() const; + void setUseBuildSystemWarnings(bool useBuildSystemWarnings); + bool operator==(const ClangDiagnosticConfig &other) const; bool operator!=(const ClangDiagnosticConfig &other) const; @@ -76,6 +79,7 @@ private: QString m_clangTidyChecks; QString m_clazyChecks; bool m_isReadOnly = false; + bool m_useBuildSystemWarnings = false; }; using ClangDiagnosticConfigs = QVector; diff --git a/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp b/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp index 68e3e443fdc..881e849b905 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp @@ -162,6 +162,18 @@ static void addConfigForTidyAndClazy(ClangDiagnosticConfigsModel &model) model.appendOrUpdate(config); } +static void addConfigForBuildSystem(ClangDiagnosticConfigsModel &model) +{ + ClangDiagnosticConfig config; + config.setId("Builtin.BuildSystem"); + config.setDisplayName(QCoreApplication::translate("ClangDiagnosticConfigsModel", + "Build-systems' warnings")); + config.setIsReadOnly(true); + config.setUseBuildSystemWarnings(true); + + model.appendOrUpdate(config); +} + static void addBuiltinConfigs(ClangDiagnosticConfigsModel &model) { addConfigForPedanticWarnings(model); @@ -171,6 +183,7 @@ static void addBuiltinConfigs(ClangDiagnosticConfigsModel &model) addConfigForClangAnalyze(model); addConfigForClazy(model); addConfigForTidyAndClazy(model); + addConfigForBuildSystem(model); } ClangDiagnosticConfigsModel::ClangDiagnosticConfigsModel(const ClangDiagnosticConfigs &customConfigs) diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp index 22e7a93b8f9..a9a32a77bd1 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -611,7 +612,7 @@ ClangDiagnosticConfigsWidget::ClangDiagnosticConfigsWidget(const Core::Id &confi this, &ClangDiagnosticConfigsWidget::onCopyButtonClicked); connect(m_ui->removeButton, &QPushButton::clicked, this, &ClangDiagnosticConfigsWidget::onRemoveButtonClicked); - connectDiagnosticOptionsChanged(); + connectClangOnlyOptionsChanged(); connect(m_tidyChecks->checksPrefixesTree, &QTreeView::clicked, @@ -734,14 +735,17 @@ static QStringList normalizeDiagnosticInputOptions(const QString &options) return options.simplified().split(QLatin1Char(' '), QString::SkipEmptyParts); } -void ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited() +void ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged() { - // Clean up input + const bool useBuildSystemWarnings = m_clangBaseChecks->useFlagsFromBuildSystemCheckBox + ->isChecked(); + + // Clean up options input const QString diagnosticOptions = m_clangBaseChecks->diagnosticOptionsTextEdit->document() ->toPlainText(); const QStringList normalizedOptions = normalizeDiagnosticInputOptions(diagnosticOptions); - // Validate + // Validate options input const QString errorMessage = validateDiagnosticOptions(normalizedOptions); updateValidityWidgets(errorMessage); if (!errorMessage.isEmpty()) { @@ -754,6 +758,7 @@ void ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited() // Commit valid changes ClangDiagnosticConfig updatedConfig = selectedConfig(); updatedConfig.setClangOptions(normalizedOptions); + updatedConfig.setUseBuildSystemWarnings(useBuildSystemWarnings); updateConfig(updatedConfig); } @@ -793,11 +798,17 @@ void ClangDiagnosticConfigsWidget::syncOtherWidgetsToComboBox() if (isConfigChooserEmpty()) return; + disconnectClangOnlyOptionsChanged(); + Utils::ExecuteOnDestruction e([this]() { connectClangOnlyOptionsChanged(); }); + const ClangDiagnosticConfig &config = selectedConfig(); // Update main button row m_ui->removeButton->setEnabled(!config.isReadOnly()); + // Update check box + m_clangBaseChecks->useFlagsFromBuildSystemCheckBox->setChecked(config.useBuildSystemWarnings()); + // Update Text Edit const QString options = m_notAcceptedOptions.contains(config.id()) ? m_notAcceptedOptions.value(config.id()) @@ -894,11 +905,8 @@ bool ClangDiagnosticConfigsWidget::isConfigChooserEmpty() const void ClangDiagnosticConfigsWidget::setDiagnosticOptions(const QString &options) { - if (options != m_clangBaseChecks->diagnosticOptionsTextEdit->document()->toPlainText()) { - disconnectDiagnosticOptionsChanged(); + if (options != m_clangBaseChecks->diagnosticOptionsTextEdit->document()->toPlainText()) m_clangBaseChecks->diagnosticOptionsTextEdit->document()->setPlainText(options); - connectDiagnosticOptionsChanged(); - } const QString errorMessage = validateDiagnosticOptions(normalizeDiagnosticInputOptions(options)); @@ -968,20 +976,28 @@ void ClangDiagnosticConfigsWidget::disconnectConfigChooserCurrentIndex() this, &ClangDiagnosticConfigsWidget::onCurrentConfigChanged); } -void ClangDiagnosticConfigsWidget::connectDiagnosticOptionsChanged() +void ClangDiagnosticConfigsWidget::connectClangOnlyOptionsChanged() { + connect(m_clangBaseChecks->useFlagsFromBuildSystemCheckBox, + &QCheckBox::stateChanged, + this, + &ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged); connect(m_clangBaseChecks->diagnosticOptionsTextEdit->document(), &QTextDocument::contentsChanged, this, - &ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited); + &ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged); } -void ClangDiagnosticConfigsWidget::disconnectDiagnosticOptionsChanged() +void ClangDiagnosticConfigsWidget::disconnectClangOnlyOptionsChanged() { + disconnect(m_clangBaseChecks->useFlagsFromBuildSystemCheckBox, + &QCheckBox::stateChanged, + this, + &ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged); disconnect(m_clangBaseChecks->diagnosticOptionsTextEdit->document(), &QTextDocument::contentsChanged, this, - &ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited); + &ClangDiagnosticConfigsWidget::onClangOnlyOptionsChanged); } ClangDiagnosticConfigs ClangDiagnosticConfigsWidget::customConfigs() const diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.h b/src/plugins/cpptools/clangdiagnosticconfigswidget.h index 502f5a62d53..39d733cea53 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.h +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.h @@ -77,7 +77,7 @@ private: void onClazyTreeChanged(); void onClangTidyTreeItemClicked(const QModelIndex &index); - void onDiagnosticOptionsEdited(); + void onClangOnlyOptionsChanged(); void syncWidgetsToModel(const Core::Id &configToSelect = Core::Id()); void syncConfigChooserToModel(const Core::Id &configToSelect = Core::Id()); @@ -104,8 +104,8 @@ private: void connectConfigChooserCurrentIndex(); void disconnectConfigChooserCurrentIndex(); - void connectDiagnosticOptionsChanged(); - void disconnectDiagnosticOptionsChanged(); + void connectClangOnlyOptionsChanged(); + void disconnectClangOnlyOptionsChanged(); private: Ui::ClangDiagnosticConfigsWidget *m_ui; diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index 6e3fa368172..3f44a977c94 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -99,12 +99,14 @@ CompilerOptionsBuilder::CompilerOptionsBuilder(const ProjectPart &projectPart, UseSystemHeader useSystemHeader, UseTweakedHeaderPaths useTweakedHeaderPaths, UseLanguageDefines useLanguageDefines, + UseBuildSystemWarnings useBuildSystemWarnings, const QString &clangVersion, const QString &clangResourceDirectory) : m_projectPart(projectPart) , m_useSystemHeader(useSystemHeader) , m_useTweakedHeaderPaths(useTweakedHeaderPaths) , m_useLanguageDefines(useLanguageDefines) + , m_useBuildSystemWarnings(useBuildSystemWarnings) , m_clangVersion(clangVersion) , m_clangResourceDirectory(clangResourceDirectory) { @@ -707,10 +709,11 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() continue; } - // Ignore warning flags as these interfere with ouser user-configured diagnostics. + // Ignore warning flags as these interfere with our user-configured diagnostics. // Note that once "-w" is provided, no warnings will be emitted, even if "-Wall" follows. - if (option.startsWith("-w", Qt::CaseInsensitive) - || option.startsWith("/w", Qt::CaseInsensitive) || option.startsWith("-pedantic")) { + if (m_useBuildSystemWarnings == UseBuildSystemWarnings::No + && (option.startsWith("-w", Qt::CaseInsensitive) + || option.startsWith("/w", Qt::CaseInsensitive) || option.startsWith("-pedantic"))) { // -w, -W, /w, /W... continue; } diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h index 4667b7a72f0..03564ab6164 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.h +++ b/src/plugins/cpptools/compileroptionsbuilder.h @@ -36,6 +36,7 @@ enum class UseSystemHeader : char { Yes, No }; enum class UseTweakedHeaderPaths : char { Yes, No }; enum class UseToolchainMacros : char { Yes, No }; enum class UseLanguageDefines : char { Yes, No }; +enum class UseBuildSystemWarnings : char { Yes, No }; CPPTOOLS_EXPORT QStringList XclangArgs(const QStringList &args); CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args); @@ -43,12 +44,14 @@ CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args); class CPPTOOLS_EXPORT CompilerOptionsBuilder { public: - CompilerOptionsBuilder(const ProjectPart &projectPart, - UseSystemHeader useSystemHeader = UseSystemHeader::No, - UseTweakedHeaderPaths useTweakedHeaderPaths = UseTweakedHeaderPaths::No, - UseLanguageDefines useLanguageDefines = UseLanguageDefines::No, - const QString &clangVersion = QString(), - const QString &clangResourceDirectory = QString()); + CompilerOptionsBuilder( + const ProjectPart &projectPart, + UseSystemHeader useSystemHeader = UseSystemHeader::No, + UseTweakedHeaderPaths useTweakedHeaderPaths = UseTweakedHeaderPaths::No, + UseLanguageDefines useLanguageDefines = UseLanguageDefines::No, + UseBuildSystemWarnings useBuildSystemWarnings = UseBuildSystemWarnings::No, + const QString &clangVersion = QString(), + const QString &clangResourceDirectory = QString()); QStringList build(ProjectFile::Kind fileKind, UsePrecompiledHeaders usePrecompiledHeaders); QStringList options() const { return m_options; } @@ -99,6 +102,7 @@ private: const UseSystemHeader m_useSystemHeader; const UseTweakedHeaderPaths m_useTweakedHeaderPaths; const UseLanguageDefines m_useLanguageDefines; + const UseBuildSystemWarnings m_useBuildSystemWarnings; const QString m_clangVersion; const QString m_clangResourceDirectory; diff --git a/tests/unit/unittest/compileroptionsbuilder-test.cpp b/tests/unit/unittest/compileroptionsbuilder-test.cpp index 4176bebc5e6..372149c0464 100644 --- a/tests/unit/unittest/compileroptionsbuilder-test.cpp +++ b/tests/unit/unittest/compileroptionsbuilder-test.cpp @@ -98,6 +98,22 @@ TEST_F(CompilerOptionsBuilder, CompilerFlagsFiltering_UnknownOptionsAreForwarded ASSERT_THAT(compilerOptionsBuilder.options(), Contains(part.compilerFlags.first())); } +TEST_F(CompilerOptionsBuilder, CompilerFlagsFiltering_WarningsFlagsAreNotFilteredIfRequested) +{ + ProjectPart part = projectPart; + part.compilerFlags = QStringList{"-Whello"}; + + CppTools::CompilerOptionsBuilder compilerOptionsBuilder{part, + CppTools::UseSystemHeader::No, + CppTools::UseTweakedHeaderPaths::No, + CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::Yes}; + + compilerOptionsBuilder.build(ProjectFile::CXXSource, CppTools::UsePrecompiledHeaders::No); + + ASSERT_THAT(compilerOptionsBuilder.options(), Contains(part.compilerFlags.first())); +} + TEST_F(CompilerOptionsBuilder, CompilerFlagsFiltering_DiagnosticOptionsAreRemoved) { ProjectPart part = projectPart; @@ -171,6 +187,7 @@ TEST_F(CompilerOptionsBuilder, HeaderPathOptionsOrder) CppTools::UseSystemHeader::No, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""}; @@ -196,6 +213,7 @@ TEST_F(CompilerOptionsBuilder, HeaderPathOptionsOrderCl) CppTools::UseSystemHeader::No, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""}; compilerOptionsBuilder.evaluateCompilerFlags(); @@ -221,6 +239,7 @@ TEST_F(CompilerOptionsBuilder, UseSystemHeader) CppTools::UseSystemHeader::Yes, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""}; @@ -265,6 +284,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderMacOs) CppTools::UseSystemHeader::No, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""); @@ -310,6 +330,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderLinux) CppTools::UseSystemHeader::No, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""); @@ -356,6 +377,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderNoVersion) CppTools::UseSystemHeader::No, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""); @@ -403,6 +425,7 @@ TEST_F(CompilerOptionsBuilder, ClangHeadersAndCppIncludesPathsOrderAndroidClang) CppTools::UseSystemHeader::No, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""); @@ -480,6 +503,7 @@ TEST_F(CompilerOptionsBuilder, InsertWrappedQtHeaders) CppTools::UseSystemHeader::Yes, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""}; @@ -613,6 +637,7 @@ TEST_F(CompilerOptionsBuilder, BuildAllOptions) CppTools::UseSystemHeader::No, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""); @@ -652,6 +677,7 @@ TEST_F(CompilerOptionsBuilder, BuildAllOptionsCl) CppTools::UseSystemHeader::No, CppTools::UseTweakedHeaderPaths::Yes, CppTools::UseLanguageDefines::No, + CppTools::UseBuildSystemWarnings::No, "dummy_version", ""); From f6c46ce35d9018335a19d8d75fda4dfd7adf69b3 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Mon, 28 Jan 2019 12:40:03 +0100 Subject: [PATCH 12/16] 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 --- .../clangdiagnostictooltipwidget.cpp | 50 +------ src/plugins/clangcodemodel/clangtextmark.cpp | 123 +++++++++++++++++- src/plugins/clangcodemodel/clangutils.cpp | 46 +++++++ src/plugins/clangcodemodel/clangutils.h | 17 +++ .../cpptools/clangdiagnosticconfigsmodel.cpp | 6 +- .../cpptools/clangdiagnosticconfigswidget.cpp | 27 ---- src/plugins/cpptools/cppcodemodelsettings.cpp | 23 +++- src/plugins/cpptools/cpptoolsreuse.cpp | 11 ++ src/plugins/cpptools/cpptoolsreuse.h | 2 + 9 files changed, 226 insertions(+), 79 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp index 497af719930..5f85a2e2263 100644 --- a/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp +++ b/src/plugins/clangcodemodel/clangdiagnostictooltipwidget.cpp @@ -25,6 +25,7 @@ #include "clangdiagnostictooltipwidget.h" #include "clangfixitoperation.h" +#include "clangutils.h" #include @@ -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); } diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index b8dc9a92a4d..41ee4c1533e 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -27,11 +27,20 @@ #include "clangconstants.h" #include "clangdiagnostictooltipwidget.h" +#include "clangeditordocumentprocessor.h" +#include "clangmodelmanagersupport.h" +#include "clangprojectsettings.h" #include "clangutils.h" -#include +#include +#include +#include +#include + +#include #include #include +#include #include #include @@ -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 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 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) diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 8a27a115a2d..481b0774f8f 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -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 diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index b7f705b57b8..4db869896b0 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -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 diff --git a/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp b/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp index 881e849b905..777dd27ca26 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigsmodel.cpp @@ -25,6 +25,7 @@ #include "clangdiagnosticconfigsmodel.h" +#include "cpptoolsreuse.h" #include "cpptoolsconstants.h" #include @@ -73,7 +74,6 @@ constexpr const char *DEFAULT_TIDY_CHECKS = "-*," "-readability-braces-around-statements," "-readability-implicit-bool-conversion," "-readability-named-parameter"; -constexpr const char *DEFAULT_CLAZY_CHECKS = "level0"; static void addConfigForAlmostEveryWarning(ClangDiagnosticConfigsModel &model) { @@ -141,7 +141,7 @@ static void addConfigForClazy(ClangDiagnosticConfigsModel &model) "Clazy level0 checks")); config.setIsReadOnly(true); config.setClangOptions(QStringList{QStringLiteral("-w")}); - config.setClazyChecks(QString::fromUtf8(DEFAULT_CLAZY_CHECKS)); + config.setClazyChecks(clazyChecksForLevel(0)); model.appendOrUpdate(config); } @@ -157,7 +157,7 @@ static void addConfigForTidyAndClazy(ClangDiagnosticConfigsModel &model) config.setClangTidyMode(ClangDiagnosticConfig::TidyMode::ChecksPrefixList); config.setClangTidyChecks(QString::fromUtf8(DEFAULT_TIDY_CHECKS)); - config.setClazyChecks(QString::fromUtf8(DEFAULT_CLAZY_CHECKS)); + config.setClazyChecks(clazyChecksForLevel(0)); model.appendOrUpdate(config); } diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp index a9a32a77bd1..6d45b428be5 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp @@ -319,16 +319,6 @@ public: m_root->checked = Qt::Unchecked; propagateDown(index(0, 0, QModelIndex())); - // <= Qt Creator 4.8 settings provide specific levels: {"level0"} - if (checks.size() == 1 && checks.first().startsWith("level")) { - bool ok = false; - const int level = checks.first().mid(5).toInt(&ok); - QTC_ASSERT(ok, return); - enableChecksByLevel(level); - return; - } - - // >= Qt Creator 4.9 settings provide specific checks: {c1, c2, ...} for (const QString &check : checks) { const QModelIndex index = indexForCheck(check); if (!index.isValid()) @@ -437,23 +427,6 @@ private: } } - void enableChecksByLevel(int level) - { - if (level < 0) - return; - - ClazyChecksTree *node = m_levelNodes.value(level); - QTC_ASSERT(node, return); - const QModelIndex index = indexForTree(node); - QTC_ASSERT(index.isValid(), return); - - node->checked = Qt::Checked; - propagateUp(index); - propagateDown(index); - - enableChecksByLevel(--level); - } - QModelIndex indexForCheck(const QString &check) const { if (check == "*") return index(0, 0, QModelIndex()); diff --git a/src/plugins/cpptools/cppcodemodelsettings.cpp b/src/plugins/cpptools/cppcodemodelsettings.cpp index 235066e6a04..35b81a9b7a5 100644 --- a/src/plugins/cpptools/cppcodemodelsettings.cpp +++ b/src/plugins/cpptools/cppcodemodelsettings.cpp @@ -27,6 +27,7 @@ #include "clangdiagnosticconfigsmodel.h" #include "cpptoolsconstants.h" +#include "cpptoolsreuse.h" #include @@ -79,6 +80,24 @@ static QString skipIndexingBigFilesKey() static QString indexerFileSizeLimitKey() { return QLatin1String(Constants::CPPTOOLS_INDEXER_FILE_SIZE_LIMIT); } +static QString convertToNewClazyChecksFormat(const QString &checks) +{ + // Before Qt Creator 4.9 valid values for checks were: "", "levelN". + // Starting with Qt Creator 4.9, checks are a comma-separated string of checks: "x,y,z". + + if (checks.isEmpty()) + return checks; + + if (checks.size() == 6 && checks.startsWith("level")) { + bool ok = false; + const int level = checks.mid(5).toInt(&ok); + QTC_ASSERT(ok, return QString()); + return clazyChecksForLevel(level); + } + + return checks; +} + static ClangDiagnosticConfigs customDiagnosticConfigsFromSettings(QSettings *s) { QTC_ASSERT(s->group() == QLatin1String(Constants::CPPTOOLS_SETTINGSGROUP), @@ -98,7 +117,9 @@ static ClangDiagnosticConfigs customDiagnosticConfigsFromSettings(QSettings *s) s->value(clangDiagnosticConfigsArrayClangTidyModeKey()).toInt())); config.setClangTidyChecks( s->value(clangDiagnosticConfigsArrayClangTidyChecksKey()).toString()); - config.setClazyChecks(s->value(clangDiagnosticConfigsArrayClazyChecksKey()).toString()); + + const QString clazyChecks = s->value(clangDiagnosticConfigsArrayClazyChecksKey()).toString(); + config.setClazyChecks(convertToNewClazyChecksFormat(clazyChecks)); configs.append(config); } s->endArray(); diff --git a/src/plugins/cpptools/cpptoolsreuse.cpp b/src/plugins/cpptools/cpptoolsreuse.cpp index 63d0a0bbc8b..c56bfb9160c 100644 --- a/src/plugins/cpptools/cpptoolsreuse.cpp +++ b/src/plugins/cpptools/cpptoolsreuse.cpp @@ -27,6 +27,7 @@ #include "cppcodemodelsettings.h" #include "cpptoolsplugin.h" +#include "cpptools_clazychecks.h" #include #include @@ -287,4 +288,14 @@ UsePrecompiledHeaders getPchUsage() return UsePrecompiledHeaders::Yes; } +QString clazyChecksForLevel(int level) +{ + QStringList checks; + for (const Constants::ClazyCheckInfo &check : Constants::CLAZY_CHECKS) { + if (check.level == level) + checks << check.name; + } + return checks.join(','); +} + } // CppTools diff --git a/src/plugins/cpptools/cpptoolsreuse.h b/src/plugins/cpptools/cpptoolsreuse.h index cb45fe89580..d1a1956be31 100644 --- a/src/plugins/cpptools/cpptoolsreuse.h +++ b/src/plugins/cpptools/cpptoolsreuse.h @@ -80,4 +80,6 @@ UsePrecompiledHeaders CPPTOOLS_EXPORT getPchUsage(); int indexerFileSizeLimitInMb(); bool fileSizeExceedsLimit(const QFileInfo &fileInfo, int sizeLimitInMb); +QString clazyChecksForLevel(int level); + } // CppTools From d4726589f15df9f27473600b8977e338fff484aa Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 31 Jan 2019 15:07:36 +0100 Subject: [PATCH 13/16] QmlDesigner: Fix error for Connections Connections is actually in QtQml. Change-Id: I88d33e273efa542535ef7f87a4020c23f172b15e Reviewed-by: Tim Jenssen --- .../qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index 3720bdc90a2..c13781558cb 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -656,7 +656,9 @@ QObject *ObjectNodeInstance::createPrimitiveFromSource(const QString &typeName, if (parts.isEmpty()) return 0; - const QString importString = parts.join(".") + " " + QString::number(majorNumber) + "." + QString::number(minorNumber); + QString importString = parts.join(".") + " " + QString::number(majorNumber) + "." + QString::number(minorNumber); + if (importString == "QtQuick 1.0") /* Workaround for implicit QQml import */ + importString = "QtQuick 2.0"; QString source = "import " + importString + "\n" + unqualifiedTypeName + " {\n" + "}\n"; return createCustomParserObject(source, "", context); } From 2c583d6c989256703f3d808db3f195e5f38779fb Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 4 Feb 2019 11:26:32 +0100 Subject: [PATCH 14/16] QmlDesigner: Catch exception Change-Id: I22db80a0d6e7a1c95f6e77f584a177aaa78253bf Reviewed-by: Tim Jenssen --- .../qmldesignerextension/pathtool/pathitem.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp b/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp index 0d5b380747d..ad5437f34e9 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp +++ b/src/plugins/qmldesigner/qmldesignerextension/pathtool/pathitem.cpp @@ -25,6 +25,7 @@ #include "pathitem.h" +#include #include #include #include @@ -840,13 +841,17 @@ void PathItem::updatePathModelNodes(const QList &changedPoints) { PathUpdateDisabler pathUpdateDisabler(this, PathUpdateDisabler::DontUpdatePath); - RewriterTransaction rewriterTransaction = - formEditorItem()->qmlItemNode().view()->beginRewriterTransaction(QByteArrayLiteral("PathItem::createCubicSegmentContextMenu")); + try { + RewriterTransaction rewriterTransaction = + formEditorItem()->qmlItemNode().view()->beginRewriterTransaction(QByteArrayLiteral("PathItem::createCubicSegmentContextMenu")); - foreach (SelectionPoint changedPoint, changedPoints) - changedPoint.controlPoint.updateModelNode(); + foreach (SelectionPoint changedPoint, changedPoints) + changedPoint.controlPoint.updateModelNode(); - rewriterTransaction.commit(); + rewriterTransaction.commit(); + } catch (const Exception &e) { + e.showException(); + } } void PathItem::disablePathUpdates() From e70a7fa6f174d349dc1f361b1774860e5634eef2 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Wed, 6 Feb 2019 09:32:45 +0100 Subject: [PATCH 15/16] .gitignore: Ignore .qmake.{cache,stash} for full tree ...and not just the top level. Change-Id: I7ff7be5d8a9336e75faa82f52e66f949f33ea0f0 Reviewed-by: Orgad Shaneh --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 10545abfcbc..5dbedd7022f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,8 +27,8 @@ *~ .#* .DS_Store -/.qmake.cache -/.qmake.stash +.qmake.cache +.qmake.stash Makefile* Thumbs.db core From 672bee2ed1172fcb024093d5698a1c81cac5f38c Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 30 Jan 2019 20:54:57 +0100 Subject: [PATCH 16/16] Don't detach temporaries [-Wclazy-detaching-temporary] Change-Id: I278873fff8592249f0c4519a4e4a6faff2dff6e3 Reviewed-by: Orgad Shaneh --- .../clangtoolspreconfiguredsessiontests.cpp | 2 +- .../clangtools/clangtoolsunittests.cpp | 2 +- .../followsymbol_switchmethoddecldef_test.cpp | 2 +- .../valgrind/valgrindtestrunnertest.cpp | 76 +++++++++---------- src/plugins/vcsbase/vcsbaseeditor.cpp | 2 +- 5 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp index 6014e008219..e31522f3719 100644 --- a/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp +++ b/src/plugins/clangtools/clangtoolspreconfiguredsessiontests.cpp @@ -223,7 +223,7 @@ bool PreconfiguredSessionTests::switchToProjectAndTarget(Project *project, SessionManager::setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade); QTC_ASSERT(spyFinishedParsing.wait(30000), return false); - const QVariant projectArgument = spyFinishedParsing.takeFirst().takeFirst(); + const QVariant projectArgument = spyFinishedParsing.takeFirst().constFirst(); QTC_ASSERT(projectArgument.canConvert(), return false); return projectArgument.value() == project; diff --git a/src/plugins/clangtools/clangtoolsunittests.cpp b/src/plugins/clangtools/clangtoolsunittests.cpp index 7cf401aa0e6..3e5d716116c 100644 --- a/src/plugins/clangtools/clangtoolsunittests.cpp +++ b/src/plugins/clangtools/clangtoolsunittests.cpp @@ -94,7 +94,7 @@ void ClangToolsUnitTests::testProject() QFETCH(int, expectedDiagCount); if (projectFilePath.contains("mingw")) { const ToolChain * const toolchain - = ToolChainKitInformation::toolChain(KitManager::kits().first(), + = ToolChainKitInformation::toolChain(KitManager::kits().constFirst(), Constants::CXX_LANGUAGE_ID); if (toolchain->typeId() != ProjectExplorer::Constants::MINGW_TOOLCHAIN_TYPEID) QSKIP("This test is mingw specific, does not run for other toolchains"); diff --git a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp index 8d30cfbd437..5a82792ad8d 100644 --- a/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp +++ b/src/plugins/cppeditor/followsymbol_switchmethoddecldef_test.cpp @@ -102,7 +102,7 @@ QT_BEGIN_NAMESPACE namespace QTest { template<> char *toString(const OverrideItem &data) { - return qstrdup(data.toByteArray().data()); + return qstrdup(data.toByteArray().constData()); } } diff --git a/src/plugins/valgrind/valgrindtestrunnertest.cpp b/src/plugins/valgrind/valgrindtestrunnertest.cpp index d4f519e3527..4a3414060ef 100644 --- a/src/plugins/valgrind/valgrindtestrunnertest.cpp +++ b/src/plugins/valgrind/valgrindtestrunnertest.cpp @@ -160,7 +160,7 @@ void ValgrindTestRunnerTest::testLeak1() QCOMPARE(error.leakedBlocks(), qint64(1)); QCOMPARE(error.leakedBytes(), quint64(8)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 2); { @@ -195,7 +195,7 @@ void ValgrindTestRunnerTest::testLeak2() QCOMPARE(error.leakedBlocks(), qint64(1)); QCOMPARE(error.leakedBytes(), quint64(5)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 3); { @@ -235,7 +235,7 @@ void ValgrindTestRunnerTest::testLeak3() QCOMPARE(error.leakedBlocks(), qint64(1)); QCOMPARE(error.leakedBytes(), quint64(5)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 3); { @@ -284,7 +284,7 @@ void ValgrindTestRunnerTest::testLeak4() QCOMPARE(error.leakedBlocks(), qint64(1)); QCOMPARE(error.leakedBytes(), quint64(8)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 3); { @@ -325,7 +325,7 @@ void ValgrindTestRunnerTest::testLeak4() else QCOMPARE(error.leakedBytes(), quint64(12)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 2); { @@ -364,11 +364,11 @@ void ValgrindTestRunnerTest::testUninit1() QCOMPARE(error.stacks().count(), 2); //BEGIN first stack { - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 4 + HEADER_LENGTH); @@ -378,11 +378,11 @@ void ValgrindTestRunnerTest::testUninit1() } //BEGIN second stack { - const Stack stack = error.stacks().last(); + const Stack stack = error.stacks().constLast(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 2 + HEADER_LENGTH); @@ -412,11 +412,11 @@ void ValgrindTestRunnerTest::testUninit2() QCOMPARE(error.stacks().count(), 2); //BEGIN first stack { - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 4 + HEADER_LENGTH); @@ -426,11 +426,11 @@ void ValgrindTestRunnerTest::testUninit2() } //BEGIN second stack { - const Stack stack = error.stacks().last(); + const Stack stack = error.stacks().constLast(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 2 + HEADER_LENGTH); @@ -445,11 +445,11 @@ void ValgrindTestRunnerTest::testUninit2() QCOMPARE(error.kind(), int(InvalidWrite)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 4 + HEADER_LENGTH); @@ -479,11 +479,11 @@ void ValgrindTestRunnerTest::testUninit3() QCOMPARE(error.stacks().count(), 2); //BEGIN first stack { - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 4 + HEADER_LENGTH); @@ -493,11 +493,11 @@ void ValgrindTestRunnerTest::testUninit3() } //BEGIN second stack { - const Stack stack = error.stacks().last(); + const Stack stack = error.stacks().constLast(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 2 + HEADER_LENGTH); @@ -512,11 +512,11 @@ void ValgrindTestRunnerTest::testUninit3() QCOMPARE(error.kind(), int(InvalidRead)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 4 + HEADER_LENGTH); @@ -543,7 +543,7 @@ void ValgrindTestRunnerTest::testSyscall() QCOMPARE(error.stacks().count(), 2); //BEGIN first stack { - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); if (on64bit()) { QCOMPARE(stack.frames().count(), 4); @@ -574,11 +574,11 @@ void ValgrindTestRunnerTest::testSyscall() } //BEGIN second stack { - const Stack stack = error.stacks().last(); + const Stack stack = error.stacks().constLast(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 1); - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 2 + HEADER_LENGTH); @@ -605,16 +605,16 @@ void ValgrindTestRunnerTest::testFree1() QVERIFY(error.stacks().count() >= 2); //BEGIN first stack { - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 2); { - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("operator delete(void*)")); } { - const Frame frame = stack.frames().last(); + const Frame frame = stack.frames().constLast(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 7 + HEADER_LENGTH); @@ -630,11 +630,11 @@ void ValgrindTestRunnerTest::testFree1() QCOMPARE(stack.frames().count(), 2); { - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("operator delete(void*)")); } { - const Frame frame = stack.frames().last(); + const Frame frame = stack.frames().constLast(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 6 + HEADER_LENGTH); @@ -662,16 +662,16 @@ void ValgrindTestRunnerTest::testFree2() QCOMPARE(error.stacks().count(), 2); //BEGIN first stack { - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 2); { - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); QCOMPARE(frame.functionName(), QString("free")); } { - const Frame frame = stack.frames().last(); + const Frame frame = stack.frames().constLast(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 6 + HEADER_LENGTH); @@ -682,20 +682,20 @@ void ValgrindTestRunnerTest::testFree2() } //BEGIN second stack { - const Stack stack = error.stacks().last(); + const Stack stack = error.stacks().constLast(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 2); { - const Frame frame = stack.frames().first(); + const Frame frame = stack.frames().constFirst(); if (on64bit()) QCOMPARE(frame.functionName(), QString("operator new(unsigned long)")); else QCOMPARE(frame.functionName(), QString("operator new(unsigned int)")); } { - const Frame frame = stack.frames().last(); + const Frame frame = stack.frames().constLast(); QCOMPARE(frame.functionName(), QString("main")); QCOMPARE(frame.line(), 5 + HEADER_LENGTH); @@ -721,7 +721,7 @@ void ValgrindTestRunnerTest::testInvalidjump() const Error error = m_errors.first(); QCOMPARE(error.kind(), int(InvalidJump)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 2); QVERIFY(!stack.auxWhat().isEmpty()); @@ -751,7 +751,7 @@ void ValgrindTestRunnerTest::testOverlap() const Error error = m_errors.first(); QCOMPARE(error.kind(), int(Overlap)); QCOMPARE(error.stacks().count(), 1); - const Stack stack = error.stacks().first(); + const Stack stack = error.stacks().constFirst(); QCOMPARE(stack.line(), qint64(-1)); QCOMPARE(stack.frames().count(), 2); { @@ -759,7 +759,7 @@ void ValgrindTestRunnerTest::testOverlap() QVERIFY(frame.functionName().startsWith("memcpy")); } { - const Frame frame = stack.frames().last(); + const Frame frame = stack.frames().constLast(); QCOMPARE(frame.functionName(), QLatin1String("main")); QCOMPARE(frame.line(), 6 + HEADER_LENGTH); diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 0c46e20cbdc..6fcfd09eae0 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -1621,7 +1621,7 @@ Core::IEditor *VcsBaseEditor::locateEditorByTag(const QString &tag) foreach (Core::IDocument *document, Core::DocumentModel::openedDocuments()) { const QVariant tagPropertyValue = document->property(tagPropertyC); if (tagPropertyValue.type() == QVariant::String && tagPropertyValue.toString() == tag) - return Core::DocumentModel::editorsForDocument(document).first(); + return Core::DocumentModel::editorsForDocument(document).constFirst(); } return nullptr; }