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 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); } 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; 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 + + + 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/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/clangeditordocumentprocessor.cpp b/src/plugins/clangcodemodel/clangeditordocumentprocessor.cpp index 8e1d06da6c6..aaca6380d2e 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) { @@ -468,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() @@ -507,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); @@ -581,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; }; @@ -602,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/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.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/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/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 4741f1ef96a..481b0774f8f 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) @@ -368,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 0a7a1127bf9..4db869896b0 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); @@ -70,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/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/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/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/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..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,19 @@ 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); +} + +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); } @@ -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 1a3031db8a0..6d45b428be5 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -318,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()) @@ -436,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()); @@ -536,7 +510,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); }); } @@ -611,7 +585,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 +708,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 +731,7 @@ void ClangDiagnosticConfigsWidget::onDiagnosticOptionsEdited() // Commit valid changes ClangDiagnosticConfig updatedConfig = selectedConfig(); updatedConfig.setClangOptions(normalizedOptions); + updatedConfig.setUseBuildSystemWarnings(useBuildSystemWarnings); updateConfig(updatedConfig); } @@ -793,11 +771,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 +878,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 +949,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/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 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); diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index b208f8ab156..d401f452ac6 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); @@ -673,6 +698,8 @@ bool Client::reset() m_openedDocument.clear(); m_serverCapabilities = ServerCapabilities(); m_dynamicCapabilities.reset(); + for (const DocumentUri &uri : m_diagnostics.keys()) + removeDiagnostics(uri); return true; } @@ -749,6 +776,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]) @@ -763,7 +809,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); @@ -823,6 +869,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; 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/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() 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", ] } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index c506d71377f..3fd6f355e8a 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,68 @@ 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 +{ + 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) + layout->addLayout(createSeparatorLayout(), 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 /*! @@ -3490,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); @@ -3516,33 +3588,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 +5833,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; 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); 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; } 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); 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", "");