From 118406346e1663ea82fe5f1eddee80759b6c2f12 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 4 Mar 2019 19:17:49 +0100 Subject: [PATCH 01/80] Clang: Fix plurals Change-Id: I150b9ccdec73ade8826b90036b59332687b84448 Reviewed-by: Leena Miettinen Reviewed-by: Ivan Donchevskii --- src/plugins/cpptools/clangdiagnosticconfigswidget.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp index e5ff4cd9f54..ea0386239f3 100644 --- a/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp +++ b/src/plugins/cpptools/clangdiagnosticconfigswidget.cpp @@ -860,11 +860,11 @@ void ClangDiagnosticConfigsWidget::syncClazyChecksGroupBox() return !m_clazySortFilterProxyModel->filterAcceptsRow(index.row(), index.parent()); }; const bool hasEnabledButHidden = m_clazyTreeModel->hasEnabledButNotVisibleChecks(isHidden); - const QString title = hasEnabledButHidden ? tr("Checks (%1 enabled, some are filtered out)") - : tr("Checks (%1 enabled)"); - - const QStringList checks = m_clazyTreeModel->enabledChecks(); - m_clazyChecks->checksGroupBox->setTitle(title.arg(checks.count())); + const int checksCount = m_clazyTreeModel->enabledChecks().count(); + const QString title = hasEnabledButHidden ? tr("Checks (%n enabled, some are filtered out)", + nullptr, checksCount) + : tr("Checks (%n enabled)", nullptr, checksCount); + m_clazyChecks->checksGroupBox->setTitle(title); } void ClangDiagnosticConfigsWidget::updateConfig(const ClangDiagnosticConfig &config) From 8b7e8abe1b7333915819f7fbe099f6d0c441a0c6 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 4 Mar 2019 19:02:00 +0100 Subject: [PATCH 02/80] Fix description of empty python project Change-Id: I9ccf09afc0fa6348454a0a23cf86812e50ecaaa0 Reviewed-by: Cristian Maureira-Fredes Reviewed-by: Leena Miettinen --- .../wizards/projects/qtforpythonapplication/empty/wizard.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json index 0f1ce91cf78..16c2646ce56 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json @@ -3,7 +3,7 @@ "supportedProjectTypes": [ "PythonProject" ], "id": "U.QtForPythonApplicationEmpty", "category": "F.Application", - "trDescription": "Creates a Qt for Python application that only the main code for a QApplication", + "trDescription": "Creates a Qt for Python application that contains only the main code for a QApplication.", "trDisplayName": "Qt for Python - Empty", "trDisplayCategory": "Application", "icon": "icon.png", From 90bc1c91daf2a17de1a5f0da223488583d8bf7dc Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 4 Mar 2019 12:38:26 +0100 Subject: [PATCH 03/80] Fix quotation marks Change-Id: I26bd4b9e965a5313569b6e0ef6f606da57b31bff Reviewed-by: Filip Bucek Reviewed-by: Rainer Keller Reviewed-by: Eike Ziller --- src/plugins/cpptools/cppfilesettingspage.ui | 4 ++-- src/plugins/cpptools/cpptoolsplugin.cpp | 2 +- src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/cpptools/cppfilesettingspage.ui b/src/plugins/cpptools/cppfilesettingspage.ui index 9edf2cd5dae..7bb13449acc 100644 --- a/src/plugins/cpptools/cppfilesettingspage.ui +++ b/src/plugins/cpptools/cppfilesettingspage.ui @@ -99,10 +99,10 @@ These prefixes are used in addition to current file name on Switch Header/Source - Uses #pragma once instead of #ifndef include guards. + Uses "#pragma once" instead of "#ifndef" include guards. - Use '#pragma once' instead of '#ifndef' guards + Use "#pragma once" instead of "#ifndef" guards diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index 8068c27d0bd..d2ca6d5d0b8 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -211,7 +211,7 @@ bool CppToolsPlugin::initialize(const QStringList &arguments, QString *error) expander->registerVariable( "Cpp:PragmaOnce", - tr("Insert #pragma once instead of #ifndef include guards into header file"), + tr("Insert \"#pragma once\" instead of \"#ifndef\" include guards into header file"), [] { return usePragmaOnce() ? QString("true") : QString(); }); return true; diff --git a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp index 8877af90457..c5f60d3e29d 100644 --- a/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp +++ b/src/plugins/remotelinux/abstractremotelinuxdeployservice.cpp @@ -203,7 +203,7 @@ void AbstractRemoteLinuxDeployService::handleDeviceSetupDone(bool success) } else { connect(d->connection, &SshConnection::connected, this, &AbstractRemoteLinuxDeployService::handleConnected); - emit progressMessage(tr("Connecting to device '%1' (%2)") + emit progressMessage(tr("Connecting to device \"%1\" (%2).") .arg(deviceConfiguration()->displayName()) .arg(deviceConfiguration()->sshParameters().host())); if (d->connection->state() == SshConnection::Unconnected) From 71c6ad7f9eaf97de40cad6d7269b333066a7b3f0 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 4 Mar 2019 16:17:08 +0100 Subject: [PATCH 04/80] Help: Improve handling of results from index lookup If help is only found by looking up in the index, show a selection dialog to the user even if there is only one result. Otherwise we create the impression that we really think that the help we find is the correct one. Also do not add the help text to the tool tip in this case. Test case: struct Foo { static void objectCreated() {} }; Change-Id: I9579302843ea2923e06f56f4b646dd101f183b3f Reviewed-by: David Schulz --- src/plugins/coreplugin/helpitem.h | 3 +-- src/plugins/help/helpplugin.cpp | 2 +- src/plugins/texteditor/basehoverhandler.cpp | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/plugins/coreplugin/helpitem.h b/src/plugins/coreplugin/helpitem.h index 15ff585ca82..c258eed0d8a 100644 --- a/src/plugins/coreplugin/helpitem.h +++ b/src/plugins/coreplugin/helpitem.h @@ -84,10 +84,9 @@ public: const Links &links() const; const Links bestLinks() const; const QString keyword() const; - -private: bool isFuzzyMatch() const; +private: QUrl m_helpUrl; QStringList m_helpIds; QString m_docMark; diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index 7703541670e..118efadd811 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -654,7 +654,7 @@ void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp) .arg(contextHelp.helpIds().join(", ")) .arg(HelpPlugin::tr("No documentation available."))); } - } else if (links.size() == 1) { + } else if (links.size() == 1 && !contextHelp.isFuzzyMatch()) { showHelpUrl(links.front().second, LocalHelpManager::contextHelpOption()); } else { QMap map; diff --git a/src/plugins/texteditor/basehoverhandler.cpp b/src/plugins/texteditor/basehoverhandler.cpp index 72e35ba5bb3..92dae73d591 100644 --- a/src/plugins/texteditor/basehoverhandler.cpp +++ b/src/plugins/texteditor/basehoverhandler.cpp @@ -145,7 +145,7 @@ void BaseHoverHandler::decorateToolTip() if (Qt::mightBeRichText(toolTip())) setToolTip(toolTip().toHtmlEscaped()); - if (lastHelpItemIdentified().isValid()) { + if (lastHelpItemIdentified().isValid() && !lastHelpItemIdentified().isFuzzyMatch()) { const QString &helpContents = lastHelpItemIdentified().extractContent(false); if (!helpContents.isEmpty()) { m_toolTip = toolTip().toHtmlEscaped(); From 6db2552868cd2e29d15115dc79c3664d0e3e84fe Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 5 Mar 2019 10:50:56 +0100 Subject: [PATCH 05/80] Update 4.9 change log Change-Id: I29e12da2c147fc5cacee80381dbb24ee6119e5b4 Reviewed-by: Leena Miettinen --- dist/changes-4.9.0.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dist/changes-4.9.0.md b/dist/changes-4.9.0.md index 5bc79fca886..1397bfe03c2 100644 --- a/dist/changes-4.9.0.md +++ b/dist/changes-4.9.0.md @@ -52,6 +52,10 @@ QMake Projects * Fixed updating of `LD_LIBRARY_PATH` environment variable (QTCREATORBUG-21475) * Fixed updating of project tree in case of wildcards in corresponding QMake variable (QTCREATORBUG-21603) +* Fixed issues with project tree when files are directly added to `RESOURCES` + (QTCREATORBUG-20103) +* Fixed that importing build unnecessarily created temporary kit + (QTCREATORBUG-18153) CMake Projects @@ -78,6 +82,8 @@ C++ Support * Clang Code Model * Added buttons for copying and ignoring diagnostics to tooltip * Fixed issue with high memory consumption (QTCREATORBUG-19543) + * Fixed inconsistency between `Follow Symbol` and `Ctrl + Click` + (QTCREATORBUG-21637) * Clang Format * Added option to format code instead of only indenting code @@ -98,6 +104,9 @@ Nim Support Debugging +* Fixed that debugger toolbar could force large minimum window size + (QTCREATORBUG-21885) +* Added pretty printing of `QSizePolicy` * GDB * Added support for rvalue references in function arguments * LLDB @@ -167,6 +176,7 @@ Windows * Added support for MSVC 2019 * Changed toolchain detection to use `vswhere` by default, which is recommended by Microsoft +* Fixed issue with UNC paths in `.pro` files (QTCREATORBUG-21881) Linux From 495f98b25652b2e2c96b4fcfd19ebb088a371f98 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 28 Feb 2019 23:37:54 +0200 Subject: [PATCH 06/80] UnitTest: Add missing enum Amends commit f009dad9ef2f286248d7da8678134f587bda22d0. Change-Id: I5288297525edc153c1aea81d2cabb1f230a8fcce Reviewed-by: Marco Bubke --- tests/unit/unittest/gtest-creator-printing.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 8427e79af8a..60f5e526cb6 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -1138,6 +1138,7 @@ const char* progressTypeToString(ClangBackEnd::ProgressType type) case ProgressType::Invalid: return "Invalid"; case ProgressType::PrecompiledHeader: return "PrecompiledHeader"; case ProgressType::Indexing: return "Indexing"; + case ProgressType::DependencyCreation: return "DependencyCreation"; } return nullptr; From f670e80c8839f2e354515935cfcc2fd0469e5544 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 14 Feb 2019 14:58:27 +0100 Subject: [PATCH 07/80] TextEditor: Allow using KSyntaxHighlighting from system Set KSYNTAXHIGHLIGHTING_LIB_DIR to the directory that contains the KSyntaxHighlighting library file (e.g. libKF5SyntaxHighlighting.{dll,dylib,so}). This will use the respective files from there and its related include files instead of the files provided by QC. If deducing the include directory depending on the library does not work you can additionally specify KSYNTAXHIGHLIGHTING_INCLUDE_DIR as well. Both variables can be set either as qmake variable or environment variable. Task-number: QTCREATORBUG-21980 Change-Id: Ie021489d930dfc46ad3e37f9fa02d09fa146ac87 Reviewed-by: David Schulz Reviewed-by: Eike Ziller --- README.md | 4 ++++ src/libs/libs.pro | 24 ++++++++++++++++--- src/plugins/texteditor/texteditor.pro | 12 ++++++++++ .../texteditor/texteditor_dependencies.pri | 18 ++++++++++++-- src/shared/syntax/syntax_shared.pri | 19 +++++++++++++++ 5 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 src/shared/syntax/syntax_shared.pri diff --git a/README.md b/README.md index f3d1b9baf01..735259eebb9 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,10 @@ You can build Qt Creator with export QBS_INSTALL_DIR=/path/to/qbs # Optional, needed for the Python enabled dumper on Windows set PYTHON_INSTALL_DIR=C:\path\to\python + # Optional, needed to use system KSyntaxHighlighting: + set KSYNTAXHIGHLIGHTING_LIB_DIR to folder holding the KSyntaxHighlighting library + # if automatic deducing of include folder fails set KSYNTAXHIGHLIGHTING_INCLUDE_DIR as well + # both variables can also be passed as qmake variables cd $SOURCE_DIRECTORY qmake -r diff --git a/src/libs/libs.pro b/src/libs/libs.pro index 8bc99461a71..26495bbbf04 100644 --- a/src/libs/libs.pro +++ b/src/libs/libs.pro @@ -31,9 +31,27 @@ for(l, SUBDIRS) { } SUBDIRS += \ - utils/process_stub.pro \ - 3rdparty/syntax-highlighting \ - 3rdparty/syntax-highlighting/data + utils/process_stub.pro + +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR) +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + # enable short information message + KSYNTAX_WARN_ON = 1 +} + +include(../shared/syntax/syntax_shared.pri) +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + SUBDIRS += \ + 3rdparty/syntax-highlighting \ + 3rdparty/syntax-highlighting/data + + equals(KSYNTAX_WARN_ON, 1) { + message("Either KSYNTAXHIGHLIGHTING_LIB_DIR does not exist or include path could not be deduced.") + unset(KSYNTAX_WARN_ON) + } +} else { + message("Using KSyntaxHighlighting provided at $${KSYNTAXHIGHLIGHTING_LIB_DIR}.") +} win32:SUBDIRS += utils/process_ctrlc_stub.pro diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro index d5bf895ee47..29231afb82c 100644 --- a/src/plugins/texteditor/texteditor.pro +++ b/src/plugins/texteditor/texteditor.pro @@ -2,7 +2,19 @@ DEFINES += TEXTEDITOR_LIBRARY QT += gui-private network printsupport xml CONFIG += exceptions CONFIG += include_source_dir # For the highlighter autotest. + +include(../../shared/syntax/syntax_shared.pri) +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) | isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + QTC_LIB_DEPENDS += syntax-highlighting +} else { + unix:!disable_external_rpath { + !macos: QMAKE_LFLAGS += -Wl,-z,origin + QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${KSYNTAXHIGHLIGHTING_LIB_DIR}) + } +} + include(../../qtcreatorplugin.pri) + SOURCES += texteditorplugin.cpp \ plaintexteditorfactory.cpp \ textdocument.cpp \ diff --git a/src/plugins/texteditor/texteditor_dependencies.pri b/src/plugins/texteditor/texteditor_dependencies.pri index c624e4cfb23..cd58e56905a 100644 --- a/src/plugins/texteditor/texteditor_dependencies.pri +++ b/src/plugins/texteditor/texteditor_dependencies.pri @@ -2,7 +2,21 @@ QTC_PLUGIN_NAME = TextEditor QTC_LIB_DEPENDS += \ aggregation \ extensionsystem \ - utils \ - syntax-highlighting + utils + QTC_PLUGIN_DEPENDS += \ coreplugin + +# needed for plugins that depend on TextEditor plugin +include(../../shared/syntax/syntax_shared.pri) +!isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + INCLUDEPATH *= $${KSYNTAXHIGHLIGHTING_INCLUDE_DIR} + LIBS *= -L$$KSYNTAXHIGHLIGHTING_LIB_DIR -lKF5SyntaxHighlighting + + linux { + QMAKE_LFLAGS += -Wl,-z,origin + QMAKE_LFLAGS += -Wl,-rpath,$$shell_quote($${KSYNTAXHIGHLIGHTING_LIB_DIR}) + } +} else { + QTC_LIB_DEPENDS += syntax-highlighting +} diff --git a/src/shared/syntax/syntax_shared.pri b/src/shared/syntax/syntax_shared.pri new file mode 100644 index 00000000000..235939d35cf --- /dev/null +++ b/src/shared/syntax/syntax_shared.pri @@ -0,0 +1,19 @@ +# KSyntaxHighlighting uses a special folder structure (may contain target arch triple for the lib), +# so expect lib folder to be specified by the user - generate include path based on this +isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR) +isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR): KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + +!exists($$KSYNTAXHIGHLIGHTING_LIB_DIR) { + unset(KSYNTAXHIGHLIGHTING_LIB_DIR) + unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) +} else { + isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + !linux: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) + else: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) + } + + !exists($$KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + unset(KSYNTAXHIGHLIGHTING_LIB_DIR) + } +} From 2484a5e209a95bf5d369372ed85a80ca7bc90f03 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 4 Mar 2019 13:40:20 +0100 Subject: [PATCH 08/80] ClangFormat: Do not apply "smart" formatting before new lines In the concept that behavior seemed fine but in practive it looks quite strange. Add comma to the dummy text inserted into the empty line to have a proper indentation for the following empty lines. Change-Id: I770af02a475e6489bdc8f44d9f84eb3c5e7398d7 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 4 +- tests/unit/unittest/clangformat-test.cpp | 41 ++++++++----------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index a53eb50adb2..ee168b301f3 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -157,7 +157,7 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); } if (closingParenBlock || prevBlock.text().endsWith(',')) - dummyText = "&& a"; + dummyText = "&& a,"; buffer.insert(utf8Offset, dummyText); extraLength += dummyText.length(); @@ -464,7 +464,7 @@ TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlo ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; if (formatWhileTyping() && (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition) - && (typedChar == QChar::Null || typedChar == ';' || typedChar == '}')) { + && (typedChar == ';' || typedChar == '}')) { // Format before current position only in case the cursor is inside the indented block. // So if cursor position is less then the block position then the current line is before // the indented block - don't trigger extra formatting in this case. diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 115ecaf763e..67c31221e51 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -32,9 +32,8 @@ namespace TextEditor { class TabSettings -{ -}; -} +{}; +} // namespace TextEditor namespace { @@ -58,10 +57,7 @@ public: : ClangFormatIndenter(doc) {} - bool formatWhileTyping() const override - { - return true; - } + bool formatWhileTyping() const override { return true; } }; class ClangFormat : public ::testing::Test @@ -104,6 +100,7 @@ protected: QTextCursor cursor{&doc}; }; +// clang-format off TEST_F(ClangFormat, IndentBasicFile) { insertLines({"int main()", @@ -365,7 +362,7 @@ TEST_F(ClangFormat, IndentEmptyLineAndKeepPreviousEmptyLines) "}")); } -TEST_F(ClangFormat, IndentFunctionBodyAndFormatBeforeIt) +TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", " int c, int d", @@ -375,8 +372,9 @@ TEST_F(ClangFormat, IndentFunctionBodyAndFormatBeforeIt) extendedIndenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d)", - "{", + ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b,", + " int c, int d", + " ) {", " ", "}")); } @@ -404,13 +402,11 @@ TEST_F(ClangFormat, ReformatToEmptyFunction) insertLines({"int foo(int a, int b, int c, int d)", "{", " ", - "}", - ""}); + "}"}); - extendedIndenter.indentBlock(doc.findBlockByNumber(4), QChar::Null, TextEditor::TabSettings()); + extendedIndenter.indentBlock(doc.findBlockByNumber(3), '}', TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d) {}", - "")); + ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b, int c, int d) {}")); } TEST_F(ClangFormat, ReformatToNonEmptyFunction) @@ -421,13 +417,12 @@ TEST_F(ClangFormat, ReformatToNonEmptyFunction) extendedIndenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b)", - "{", + ASSERT_THAT(documentLines(), ElementsAre("int foo(int a, int b) {", " ", "}")); } -TEST_F(ClangFormat, IndentIfBodyAndFormatBeforeIt) +TEST_F(ClangFormat, IndentClosingScopeAndFormatBeforeIt) { insertLines({"if(a && b", " &&c && d", @@ -435,10 +430,9 @@ TEST_F(ClangFormat, IndentIfBodyAndFormatBeforeIt) "", "}"}); - extendedIndenter.indentBlock(doc.findBlockByNumber(3), QChar::Null, TextEditor::TabSettings()); + extendedIndenter.indentBlock(doc.findBlockByNumber(4), '}', TextEditor::TabSettings()); ASSERT_THAT(documentLines(), ElementsAre("if (a && b && c && d) {", - " ", "}")); } @@ -496,7 +490,7 @@ TEST_F(ClangFormat, IndentAndFormatCompleteStatementOnClosingScope) "}")); } -TEST_F(ClangFormat, IndentAndFormatWithEmptyLines) +TEST_F(ClangFormat, OnlyIndentClosingParenthesis) { insertLines({"foo(a,", " ", @@ -505,7 +499,7 @@ TEST_F(ClangFormat, IndentAndFormatWithEmptyLines) extendedIndenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); ASSERT_THAT(documentLines(), ElementsAre("foo(a,", - "", + " ", " )")); } @@ -622,5 +616,6 @@ TEST_F(ClangFormat, FormatTemplateparameters) ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template")); } +// clang-format on -} +} // namespace From bf972bcb01d57a7143eba4397e69e1db3a8d693b Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 5 Mar 2019 13:12:44 +0100 Subject: [PATCH 09/80] ClangFormat: Change the logic how configuration is picked Let's use by default the configuration that clang-format picks itself for the source file. The Qt Creator configuration will now only override the default one with global or project settings and can be turned off with the checkbox. This behavior is clearer than always picking some configuration which Qt Creator prefers best. Change-Id: If5ed3d67eb6b4b47a6d0fd5259f7efbb608914d1 Reviewed-by: Marco Bubke Reviewed-by: Leena Miettinen --- .../clangformat/clangformatconfigwidget.cpp | 83 +++++++++------- .../clangformat/clangformatconfigwidget.ui | 14 +-- .../clangformat/clangformatconstants.h | 1 + .../clangformat/clangformatindenter.cpp | 2 +- .../clangformat/clangformatsettings.cpp | 13 +++ src/plugins/clangformat/clangformatsettings.h | 6 ++ src/plugins/clangformat/clangformatutils.cpp | 94 +++++++++++++------ src/plugins/clangformat/clangformatutils.h | 3 + 8 files changed, 143 insertions(+), 73 deletions(-) diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index faaf6d937ff..27192a67f64 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -59,6 +59,24 @@ ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *proje { m_ui->setupUi(this); + m_preview = new TextEditor::SnippetEditorWidget(this); + m_ui->horizontalLayout_2->addWidget(m_preview); + if (m_project) { + m_ui->applyButton->show(); + hideGlobalCheckboxes(); + m_ui->overrideDefault->setChecked( + m_project->namedSettings(Constants::OVERRIDE_FILE_ID).toBool()); + } else { + m_ui->applyButton->hide(); + showGlobalCheckboxes(); + m_ui->overrideDefault->setChecked(ClangFormatSettings::instance().overrideDefaultFile()); + } + + connect(m_ui->overrideDefault, &QCheckBox::toggled, this, [this](bool checked) { + if (checked) + createStyleFileIfNeeded(!m_project); + initialize(); + }); initialize(); } @@ -81,15 +99,18 @@ void ClangFormatConfigWidget::showGlobalCheckboxes() m_ui->formatOnSave->show(); } +static bool projectConfigExists() +{ + return Utils::FileName::fromString(Core::ICore::userResourcePath()) + .appendPath(currentProjectUniqueId()) + .appendPath((Constants::SETTINGS_FILE_NAME)) + .exists(); +} + void ClangFormatConfigWidget::initialize() { - m_ui->projectHasClangFormat->show(); - m_ui->clangFormatOptionsTable->show(); - m_ui->applyButton->show(); - hideGlobalCheckboxes(); + m_ui->projectHasClangFormat->hide(); - m_preview = new TextEditor::SnippetEditorWidget(this); - m_ui->horizontalLayout_2->addWidget(m_preview); m_preview->setPlainText(QLatin1String(CppTools::Constants::DEFAULT_CODE_STYLE_SNIPPETS[0])); m_preview->textDocument()->setIndenter(new ClangFormatIndenter(m_preview->document())); m_preview->textDocument()->setFontSettings(TextEditor::TextEditorSettings::fontSettings()); @@ -103,21 +124,15 @@ void ClangFormatConfigWidget::initialize() if (lastItem->spacerItem()) m_ui->verticalLayout->removeItem(lastItem); - if (m_project - && !m_project->projectDirectory().appendPath(Constants::SETTINGS_FILE_NAME).exists()) { - m_ui->projectHasClangFormat->setText(tr("No .clang-format file for the project.")); + if (!m_ui->overrideDefault->isChecked()) { m_ui->clangFormatOptionsTable->hide(); - m_ui->applyButton->hide(); + m_preview->hide(); m_ui->verticalLayout->addStretch(1); - - connect(m_ui->createFileButton, &QPushButton::clicked, this, [this]() { - createStyleFileIfNeeded(false); - initialize(); - }); return; } - m_ui->createFileButton->hide(); + m_ui->clangFormatOptionsTable->show(); + m_preview->show(); Utils::FileName fileName; if (m_project) { @@ -126,19 +141,13 @@ void ClangFormatConfigWidget::initialize() fileName = m_project->projectFilePath().appendPath("snippet.cpp"); } else { const Project *currentProject = SessionManager::startupProject(); - if (!currentProject - || !currentProject->projectDirectory() - .appendPath(Constants::SETTINGS_FILE_NAME) - .exists()) { + if (!currentProject || !projectConfigExists()) { m_ui->projectHasClangFormat->hide(); } else { m_ui->projectHasClangFormat->setText( - tr("Current project has its own .clang-format file " + tr("Current project has its own overridden .clang-format file " "and can be configured in Projects > Code Style > C++.")); } - createStyleFileIfNeeded(true); - showGlobalCheckboxes(); - m_ui->applyButton->hide(); fileName = Utils::FileName::fromString(Core::ICore::userResourcePath()) .appendPath("snippet.cpp"); } @@ -160,7 +169,7 @@ void ClangFormatConfigWidget::fillTable() { clang::format::FormatStyle style = m_project ? currentProjectStyle() : currentGlobalStyle(); - std::string configText = clang::format::configurationAsText(style); + const std::string configText = clang::format::configurationAsText(style); m_ui->clangFormatOptionsTable->setPlainText(QString::fromStdString(configText)); } @@ -168,13 +177,16 @@ ClangFormatConfigWidget::~ClangFormatConfigWidget() = default; void ClangFormatConfigWidget::apply() { + ClangFormatSettings &settings = ClangFormatSettings::instance(); if (!m_project) { - ClangFormatSettings &settings = ClangFormatSettings::instance(); settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked()); settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked()); settings.setFormatOnSave(m_ui->formatOnSave->isChecked()); - settings.write(); + settings.setOverrideDefaultFile(m_ui->overrideDefault->isChecked()); + } else { + m_project->setNamedSettings(Constants::OVERRIDE_FILE_ID, m_ui->overrideDefault->isChecked()); } + settings.write(); const QString text = m_ui->clangFormatOptionsTable->toPlainText(); clang::format::FormatStyle style; @@ -184,16 +196,18 @@ void ClangFormatConfigWidget::apply() QMessageBox::warning(this, tr("Error in ClangFormat configuration"), QString::fromStdString(error.message())); - fillTable(); - updatePreview(); + if (m_ui->overrideDefault->isChecked()) { + fillTable(); + updatePreview(); + } return; } - QString filePath; + QString filePath = Core::ICore::userResourcePath(); if (m_project) - filePath = m_project->projectDirectory().appendPath(Constants::SETTINGS_FILE_NAME).toString(); - else - filePath = Core::ICore::userResourcePath() + "/" + Constants::SETTINGS_FILE_NAME; + filePath += "/" + currentProjectUniqueId(); + filePath += "/" + QLatin1String(Constants::SETTINGS_FILE_NAME); + QFile file(filePath); if (!file.open(QFile::WriteOnly)) return; @@ -201,7 +215,8 @@ void ClangFormatConfigWidget::apply() file.write(text.toUtf8()); file.close(); - updatePreview(); + if (m_ui->overrideDefault->isChecked()) + updatePreview(); } } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui index 41e40ef1fdc..c8225981f59 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.ui +++ b/src/plugins/clangformat/clangformatconfigwidget.ui @@ -54,6 +54,13 @@ + + + + Override Clang Format configuration file + + + @@ -63,13 +70,6 @@ - - - - Create Clang Format Configuration File - - - diff --git a/src/plugins/clangformat/clangformatconstants.h b/src/plugins/clangformat/clangformatconstants.h index 8b7cbcf9bd2..65ea9b6e81f 100644 --- a/src/plugins/clangformat/clangformatconstants.h +++ b/src/plugins/clangformat/clangformatconstants.h @@ -34,5 +34,6 @@ static const char SETTINGS_ID[] = "ClangFormat"; static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent"; static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; +static const char OVERRIDE_FILE_ID[] = "ClangFormat.OverrideFile"; } // namespace Constants } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index 42cedb7b6c9..381762ee7f2 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -57,7 +57,7 @@ bool ClangFormatIndenter::formatWhileTyping() const Utils::optional ClangFormatIndenter::tabSettings() const { - FormatStyle style = currentProjectStyle(); + FormatStyle style = styleForFile(); TabSettings tabSettings; switch (style.UseTab) { diff --git a/src/plugins/clangformat/clangformatsettings.cpp b/src/plugins/clangformat/clangformatsettings.cpp index 8be2b3cefee..8f70130ae3a 100644 --- a/src/plugins/clangformat/clangformatsettings.cpp +++ b/src/plugins/clangformat/clangformatsettings.cpp @@ -46,6 +46,8 @@ ClangFormatSettings::ClangFormatSettings() .toBool(); m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false) .toBool(); + m_overrideDefaultFile = settings->value(QLatin1String(Constants::OVERRIDE_FILE_ID), false) + .toBool(); settings->endGroup(); } @@ -57,6 +59,7 @@ void ClangFormatSettings::write() const m_formatCodeInsteadOfIndent); settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping); settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave); + settings->setValue(QLatin1String(Constants::OVERRIDE_FILE_ID), m_overrideDefaultFile); settings->endGroup(); } @@ -90,4 +93,14 @@ bool ClangFormatSettings::formatOnSave() const return m_formatOnSave; } +void ClangFormatSettings::setOverrideDefaultFile(bool enable) +{ + m_overrideDefaultFile = enable; +} + +bool ClangFormatSettings::overrideDefaultFile() const +{ + return m_overrideDefaultFile; +} + } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatsettings.h b/src/plugins/clangformat/clangformatsettings.h index 0ea9ed9747e..9344cf34a96 100644 --- a/src/plugins/clangformat/clangformatsettings.h +++ b/src/plugins/clangformat/clangformatsettings.h @@ -25,6 +25,8 @@ #pragma once +#include + namespace ClangFormat { class ClangFormatSettings @@ -43,10 +45,14 @@ public: void setFormatOnSave(bool enable); bool formatOnSave() const; + + void setOverrideDefaultFile(bool enable); + bool overrideDefaultFile() const; private: bool m_formatCodeInsteadOfIndent = false; bool m_formatWhileTyping = false; bool m_formatOnSave = false; + bool m_overrideDefaultFile = false; }; } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index babe94da24f..36bcf2f97d0 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -26,6 +26,7 @@ #include "clangformatutils.h" #include "clangformatconstants.h" +#include "clangformatsettings.h" #include #include @@ -33,6 +34,8 @@ #include #include +#include + using namespace clang; using namespace format; using namespace llvm; @@ -92,13 +95,26 @@ static void applyCppCodeStyleSettings(clang::format::FormatStyle &style, : - static_cast(style.IndentWidth); } -static Utils::FileName projectPath() +static bool useGlobalOverriddenSettings() +{ + return ClangFormatSettings::instance().overrideDefaultFile(); +} + +QString currentProjectUniqueId() { const Project *project = SessionManager::startupProject(); - if (project) - return project->projectDirectory(); + if (!project) + return QString(); - return Utils::FileName(); + return QString::fromUtf8(QCryptographicHash::hash(project->projectFilePath().toString().toUtf8(), + QCryptographicHash::Md5) + .toHex(0)); +} + +static bool useProjectOverriddenSettings() +{ + const Project *project = SessionManager::startupProject(); + return project ? project->namedSettings(Constants::OVERRIDE_FILE_ID).toBool() : false; } static Utils::FileName globalPath() @@ -106,25 +122,40 @@ static Utils::FileName globalPath() return Utils::FileName::fromString(Core::ICore::userResourcePath()); } -static QString configForFile(Utils::FileName fileName) +static Utils::FileName projectPath() { - Utils::FileName topProjectPath = projectPath(); - if (topProjectPath.isEmpty()) - return QString(); + const Project *project = SessionManager::startupProject(); + if (project) + return globalPath().appendPath("clang-format").appendPath(currentProjectUniqueId()); - QDir projectDir(fileName.parentDir().toString()); - while (!projectDir.exists(Constants::SETTINGS_FILE_NAME) - && !projectDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { - if (projectDir.path() == topProjectPath.toString() - || !Utils::FileName::fromString(projectDir.path()).isChildOf(topProjectPath) - || !projectDir.cdUp()) { - return QString(); - } + return Utils::FileName(); +} + +static QString configForFile(Utils::FileName fileName, bool checkForSettings) +{ + QDir overrideDir; + if (!checkForSettings || useProjectOverriddenSettings()) { + overrideDir = projectPath().toString(); + if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME)) + return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); } - if (projectDir.exists(Constants::SETTINGS_FILE_NAME)) - return projectDir.filePath(Constants::SETTINGS_FILE_NAME); - return projectDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); + if (!checkForSettings || useGlobalOverriddenSettings()) { + overrideDir = globalPath().toString(); + if (!overrideDir.isEmpty() && overrideDir.exists(Constants::SETTINGS_FILE_NAME)) + return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); + } + + QDir parentDir(fileName.parentDir().toString()); + while (!parentDir.exists(Constants::SETTINGS_FILE_NAME) + && !parentDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { + if (!parentDir.cdUp()) + return QString(); + } + + if (parentDir.exists(Constants::SETTINGS_FILE_NAME)) + return parentDir.filePath(Constants::SETTINGS_FILE_NAME); + return parentDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); } static clang::format::FormatStyle constructStyle(bool isGlobal, @@ -169,6 +200,7 @@ void createStyleFileIfNeeded(bool isGlobal) if (QFile::exists(configFile)) return; + QDir().mkpath(path.parentDir().toString()); std::fstream newStyleFile(configFile.toStdString(), std::fstream::out); if (newStyleFile.is_open()) { newStyleFile << clang::format::configurationAsText(constructStyle(isGlobal)); @@ -198,16 +230,11 @@ static QByteArray configBaseStyleName(const QString &configFile) .trimmed(); } -clang::format::FormatStyle styleForFile(Utils::FileName fileName) +static clang::format::FormatStyle styleForFile(Utils::FileName fileName, bool checkForSettings) { - bool isGlobal = false; - QString configFile = configForFile(fileName); - if (configFile.isEmpty()) { - Utils::FileName path = fileName = globalPath(); - fileName.appendPath(Constants::SAMPLE_FILE_NAME); - createStyleFileIfNeeded(true); - configFile = path.appendPath(Constants::SETTINGS_FILE_NAME).toString(); - } + QString configFile = configForFile(fileName, checkForSettings); + if (configFile.isEmpty()) + return constructStyle(true); Expected style = format::getStyle("file", fileName.toString().toStdString(), @@ -219,17 +246,22 @@ clang::format::FormatStyle styleForFile(Utils::FileName fileName) // do nothing }); - return constructStyle(isGlobal, configBaseStyleName(configFile)); + return constructStyle(true, configBaseStyleName(configFile)); +} + +clang::format::FormatStyle styleForFile(Utils::FileName fileName) +{ + return styleForFile(fileName, true); } clang::format::FormatStyle currentProjectStyle() { - return styleForFile(projectPath().appendPath(Constants::SAMPLE_FILE_NAME)); + return styleForFile(projectPath().appendPath(Constants::SAMPLE_FILE_NAME), false); } clang::format::FormatStyle currentGlobalStyle() { - return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME)); + return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME), false); } } diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h index 41e2b5611fa..2c818ffe6aa 100644 --- a/src/plugins/clangformat/clangformatutils.h +++ b/src/plugins/clangformat/clangformatutils.h @@ -25,6 +25,7 @@ #pragma once +#include #include #include @@ -37,6 +38,8 @@ namespace ClangFormat { // Creates the style for the current project or the global style if needed. void createStyleFileIfNeeded(bool isGlobal); +QString currentProjectUniqueId(); + clang::format::FormatStyle currentProjectStyle(); clang::format::FormatStyle currentGlobalStyle(); From cde7ae47aa43a1a63ba1bb5647c9fbfb36bad119 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 1 Mar 2019 17:01:38 +0100 Subject: [PATCH 10/80] Timeline Editor: Fix UI text Change-Id: I705605b1bfc799fad8805a87925165bef0aec3a7 Reviewed-by: Thomas Hartmann --- .../timelineeditor/timelineanimationform.ui | 18 +++++++++--------- .../timelineeditor/timelineconstants.h | 10 +++++----- .../timelineeditor/timelineform.ui | 10 +++++----- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui index 8bc3e6c9737..a27f10f4acd 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui @@ -17,7 +17,7 @@ - Loops + Loops: @@ -117,7 +117,7 @@ - Animation ID + Animation ID: @@ -162,14 +162,14 @@ - Finished + Finished: - Ping Pong + Ping pong @@ -205,7 +205,7 @@ - Transition to state + Transition to state: @@ -222,7 +222,7 @@ true - Running in Base State + Running in base state @@ -257,7 +257,7 @@ - Start Frame + Start frame: @@ -290,14 +290,14 @@ - Duration + Duration: - End Frame + End frame: diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h index 40e4900442d..b6c087aee4b 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -46,13 +46,13 @@ const int priorityTimelineCategory = 110; const char timelineCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Timeline"); const char timelineCopyKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Copy All Keyframes from item"); + "Copy All Keyframes from Item"); const char timelinePasteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Paste Keyframes to item"); + "Paste Keyframes to Item"); const char timelineInsertKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Insert Keyframes for item"); + "Insert Keyframes for Item"); const char timelineDeleteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Delete All Keyframes for item"); + "Delete All Keyframes for Item"); const char timelineStatusBarFrameNumber[] = QT_TRANSLATE_NOOP("QmlDesignerTimeline", "Frame %1"); diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui index 5eea257be19..4f063de02da 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui @@ -84,7 +84,7 @@ - Expression Binding + Expression binding: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -107,7 +107,7 @@ - End Frame + End frame: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -200,7 +200,7 @@ false - Expression Binding + Expression binding @@ -214,7 +214,7 @@ - Timeline ID + Timeline ID: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter @@ -243,7 +243,7 @@ - Start Frame + Start frame: Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter From 4a3d6f46949befe1ac7f67e71e0b67789c041483 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 5 Mar 2019 18:10:30 +0100 Subject: [PATCH 11/80] Debugger: Filter out lldb-mi entries from autodetected debuggers lldb-mi is not mimicing a full GDB, and it a safe assumption that there's a working LLDB nearby. Change-Id: I2711a7a72fad4c44e430166ede186be148a6fc7c Reviewed-by: Orgad Shaneh --- src/plugins/debugger/debuggeritemmanager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 1cd8b3ec094..6891d43faf3 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -750,7 +750,8 @@ void DebuggerItemManagerPrivate::autoDetectGdbOrLldbDebuggers() dir.setPath(base.toFileInfo().absoluteFilePath()); foreach (const QString &entry, dir.entryList()) { if (entry.startsWith("lldb-platform-") - || entry.startsWith("lldb-gdbserver-")) { + || entry.startsWith("lldb-gdbserver-") + || entry.startsWith("lldb-mi-")) { continue; } suspects.append(FileName::fromString(dir.absoluteFilePath(entry))); From 31e549a7dce3b7f3c6dedc0f014162784e6cff08 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 1 Mar 2019 14:58:57 +0100 Subject: [PATCH 12/80] Debugger: Improve lldb breakpoint handling Inform QC about changed breakpoints on the LLDB side. Fixes: QTCREATORBUG-21997 Change-Id: Icec25725f92d8a0b47f7dab2971c0c5eb5b23757 Reviewed-by: hjk --- share/qtcreator/debugger/lldbbridge.py | 24 +++++++++++++++++++++ src/plugins/debugger/lldb/lldbengine.cpp | 27 ++++++++++++++++++++++++ src/plugins/debugger/lldb/lldbengine.h | 1 + 3 files changed, 52 insertions(+) diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index a961569cd03..cf19c1eac83 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -957,6 +957,12 @@ class Dumper(DumperBase): return self.report('pid="%s"' % self.process.GetProcessID()) self.reportState('enginerunandinferiorrunok') + if self.target is not None: + broadcaster = self.target.GetBroadcaster() + listener = self.debugger.GetListener() + broadcaster.AddListener(listener, lldb.SBTarget.eBroadcastBitBreakpointChanged) + listener.StartListeningForEvents(broadcaster, lldb.SBTarget.eBroadcastBitBreakpointChanged) + def loop(self): event = lldb.SBEvent() @@ -1116,6 +1122,11 @@ class Dumper(DumperBase): # logview pane feature. self.report('token(\"%s\")' % args["token"]) + + def reportBreakpointUpdate(self, bp): + self.report('breakpointmodified={%s}' % self.describeBreakpoint(bp)) + + def readRawMemory(self, address, size): if size == 0: return bytes() @@ -1288,7 +1299,20 @@ class Dumper(DumperBase): self.process.Kill() self.reportResult('', args) + + def handleBreakpointEvent(self, event): + eventType = lldb.SBBreakpoint.GetBreakpointEventTypeFromEvent(event) + # handle only the resolved locations for now.. + if eventType & lldb.eBreakpointEventTypeLocationsResolved: + bp = lldb.SBBreakpoint.GetBreakpointFromEvent(event) + if bp is not None: + self.reportBreakpointUpdate(bp) + + def handleEvent(self, event): + if lldb.SBBreakpoint.EventIsBreakpointEvent(event): + self.handleBreakpointEvent(event) + return out = lldb.SBStream() event.GetDescription(out) #warn("EVENT: %s" % event) diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 0dee8826a7f..f91240bb939 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -395,6 +395,8 @@ void LldbEngine::handleResponse(const QString &response) handleOutputNotification(item); else if (name == "pid") notifyInferiorPid(item.toProcessHandle()); + else if (name == "breakpointmodified") + handleInterpreterBreakpointModified(item); } } @@ -607,6 +609,31 @@ void LldbEngine::handleOutputNotification(const GdbMi &output) showMessage(data, ch); } +void LldbEngine::handleInterpreterBreakpointModified(const GdbMi &bpItem) +{ + QTC_ASSERT(bpItem.childCount(), return); + QString id = bpItem.childAt(0).m_data; + + Breakpoint bp = breakHandler()->findBreakpointByResponseId(id); + if (!bp) // FIXME adapt whole bp handling and turn into soft assert + return; + + // this function got triggered by a lldb internal breakpoint event + // avoid asserts regarding unexpected state transitions + switch (bp->state()) { + case BreakpointInsertionRequested: // was a pending bp + bp->gotoState(BreakpointInsertionProceeding, BreakpointInsertionRequested); + break; + case BreakpointInserted: // was an inserted, gets updated now + bp->gotoState(BreakpointUpdateRequested, BreakpointInserted); + notifyBreakpointChangeProceeding(bp); + break; + default: + break; + } + updateBreakpointData(bp, bpItem, false); +} + void LldbEngine::loadSymbols(const QString &moduleName) { Q_UNUSED(moduleName) diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index f06798dd392..6c5b3c2c21c 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -120,6 +120,7 @@ private: void handleStateNotification(const GdbMi &item); void handleLocationNotification(const GdbMi &location); void handleOutputNotification(const GdbMi &output); + void handleInterpreterBreakpointModified(const GdbMi &item); void handleResponse(const QString &data); void updateAll() override; From 5bb8e678467ae6b1ee9d15ead673b06543740969 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 5 Mar 2019 17:13:45 +0100 Subject: [PATCH 13/80] ClangFormat: Do not save settings if they are not overridden Apply only settings from checkboxes in that case. Change-Id: Ic6740ab9d769730bba4d04dcdde7ad1e2a464614 Reviewed-by: Marco Bubke --- src/plugins/clangformat/clangformatconfigwidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index 27192a67f64..feb61f3276a 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -188,6 +188,9 @@ void ClangFormatConfigWidget::apply() } settings.write(); + if (!m_ui->overrideDefault->isChecked()) + return; + const QString text = m_ui->clangFormatOptionsTable->toPlainText(); clang::format::FormatStyle style; style.Language = clang::format::FormatStyle::LK_Cpp; From dc9c9249fcfb822a02131f4121e2b71522a0066c Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 5 Mar 2019 17:14:42 +0100 Subject: [PATCH 14/80] ClangFormat: Try to use existing file to override settings If there is a .clang-format file in the project use it as a base for the custom file that creator uses to override the project settings. Change-Id: I0786dbdd6077b87d4dd428981e24d503668f1031 Reviewed-by: Marco Bubke --- src/plugins/clangformat/clangformatutils.cpp | 36 ++++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 36bcf2f97d0..bfe0e43cfd6 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -131,6 +131,20 @@ static Utils::FileName projectPath() return Utils::FileName(); } +static QString findConfig(Utils::FileName fileName) +{ + QDir parentDir(fileName.parentDir().toString()); + while (!parentDir.exists(Constants::SETTINGS_FILE_NAME) + && !parentDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { + if (!parentDir.cdUp()) + return QString(); + } + + if (parentDir.exists(Constants::SETTINGS_FILE_NAME)) + return parentDir.filePath(Constants::SETTINGS_FILE_NAME); + return parentDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); +} + static QString configForFile(Utils::FileName fileName, bool checkForSettings) { QDir overrideDir; @@ -146,16 +160,7 @@ static QString configForFile(Utils::FileName fileName, bool checkForSettings) return overrideDir.filePath(Constants::SETTINGS_FILE_NAME); } - QDir parentDir(fileName.parentDir().toString()); - while (!parentDir.exists(Constants::SETTINGS_FILE_NAME) - && !parentDir.exists(Constants::SETTINGS_FILE_ALT_NAME)) { - if (!parentDir.cdUp()) - return QString(); - } - - if (parentDir.exists(Constants::SETTINGS_FILE_NAME)) - return parentDir.filePath(Constants::SETTINGS_FILE_NAME); - return parentDir.filePath(Constants::SETTINGS_FILE_ALT_NAME); + return findConfig(fileName); } static clang::format::FormatStyle constructStyle(bool isGlobal, @@ -201,6 +206,17 @@ void createStyleFileIfNeeded(bool isGlobal) return; QDir().mkpath(path.parentDir().toString()); + if (!isGlobal) { + const Project *project = SessionManager::startupProject(); + Utils::FileName possibleProjectConfig = project->rootProjectDirectory().appendPath( + Constants::SETTINGS_FILE_NAME); + if (possibleProjectConfig.exists()) { + // Just copy th .clang-format if current project has one. + QFile::copy(possibleProjectConfig.toString(), configFile); + return; + } + } + std::fstream newStyleFile(configFile.toStdString(), std::fstream::out); if (newStyleFile.is_open()) { newStyleFile << clang::format::configurationAsText(constructStyle(isGlobal)); From ad8cabdf45143423717513778afcbd2e4485a685 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 5 Mar 2019 17:16:29 +0100 Subject: [PATCH 15/80] ClangFormat: Do not remove empty lines while only indenting Insert dummy text into empty lines also for the electic characters not to remove empty lines when only indentation is intended. Fixes: QTCREATORBUG-22050 Change-Id: Ife5374459feb510a0587880a6772c90a2d68d70e Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 18 +++--------------- tests/unit/unittest/clangformat-test.cpp | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index ee168b301f3..09ae5a6bccb 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -355,23 +355,11 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision()); adjustFormatStyleForLineBreak(style, replacementsToKeep); - if (typedChar == QChar::Null) { - if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore) { - if (utf8Offset > 0) { - buffer.insert(utf8Offset - 1, " //"); - utf8Offset += 3; - } + if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) { + for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { utf8Length += forceIndentWithExtraText(buffer, - cursorPositionInEditor < 0 - ? endBlock - : m_doc->findBlock(cursorPositionInEditor), + m_doc->findBlockByNumber(index), secondTry); - } else { - for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { - utf8Length += forceIndentWithExtraText(buffer, - m_doc->findBlockByNumber(index), - secondTry); - } } } diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 67c31221e51..5f0aaf1d873 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -362,6 +362,23 @@ TEST_F(ClangFormat, IndentEmptyLineAndKeepPreviousEmptyLines) "}")); } +TEST_F(ClangFormat, IndentOnElectricCharacterButNotRemoveEmptyLinesBefore) +{ + insertLines({"{", + " ", + " ", + "if ()", + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(3), '(', TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("{", + " ", + " ", + " if ()", + "}")); +} + TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", From 1c0f83cd90dac9c384099f7ffd311d03e880bcf4 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 6 Mar 2019 09:18:32 +0100 Subject: [PATCH 16/80] Utils: fix memory leak in normalizePathName on windows The PIDLIST_ABSOLUTE item returned by SHParseDisplayName has to be freed again by ILFree according to the documentation of ITEMIDLIST structure. Change-Id: I29eb7576600287cdc8380e81a83ce2af79e13e33 Reviewed-by: Oliver Wolff --- src/libs/utils/fileutils.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 708595aa4d8..a476cd8d892 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -311,9 +311,10 @@ QString FileUtils::normalizePathName(const QString &name) if (FAILED(hr)) return name; TCHAR buffer[MAX_PATH]; - if (!SHGetPathFromIDList(file, buffer)) - return name; - return QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast(buffer))); + const bool success = SHGetPathFromIDList(file, buffer); + ILFree(file); + return success ? QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast(buffer))) + : name; #elif defined(Q_OS_OSX) return Internal::normalizePathName(name); #else // do not try to handle case-insensitive file systems on Linux From b0eec87e3943af8bfed4279934074e8a385ab5f9 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 4 Mar 2019 15:15:42 +0100 Subject: [PATCH 17/80] TextEditor: add tooltip to reset highlight definitions button Task-number: QTCREATORBUG-22075 Change-Id: I6d1d55fd171d412cddb3cecb160fa6d267421a8a Reviewed-by: Leena Miettinen Reviewed-by: Christian Stenger --- src/plugins/texteditor/highlightersettingspage.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/texteditor/highlightersettingspage.ui b/src/plugins/texteditor/highlightersettingspage.ui index fcd4919b128..7b1e6c9e0da 100644 --- a/src/plugins/texteditor/highlightersettingspage.ui +++ b/src/plugins/texteditor/highlightersettingspage.ui @@ -127,6 +127,9 @@ + + Reset definitions remembered for files that can be associated with more than one highlighter definition. + Reset Remembered Definitions From 762bcc5c39f88b0771cb6270499562d5320f3338 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Fri, 1 Mar 2019 14:30:02 +0100 Subject: [PATCH 18/80] Debugger: inform user about misconfigured debugger settings Change-Id: I304ae5147e04a89cd93800f8c44e82bd507f2d20 Reviewed-by: hjk Reviewed-by: Christian Stenger --- src/plugins/debugger/debuggerruncontrol.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/plugins/debugger/debuggerruncontrol.cpp b/src/plugins/debugger/debuggerruncontrol.cpp index a664d30c406..c72fcb6228b 100644 --- a/src/plugins/debugger/debuggerruncontrol.cpp +++ b/src/plugins/debugger/debuggerruncontrol.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -564,6 +565,17 @@ void DebuggerRunTool::start() if (!fixupParameters()) return; + if (m_runParameters.cppEngineType == CdbEngineType + && Utils::is64BitWindowsBinary(m_runParameters.inferior.executable) + && !Utils::is64BitWindowsBinary(m_runParameters.debugger.executable)) { + reportFailure( + DebuggerPlugin::tr( + "%1 is a 64 bit executable which can not be debugged by a 32 bit Debugger.\n" + "Please select a 64 bit Debugger in the kit settings for this kit.") + .arg(m_runParameters.inferior.executable)); + return; + } + Utils::globalMacroExpander()->registerFileVariables( "DebuggedExecutable", tr("Debugged executable"), [this] { return m_runParameters.inferior.executable; } From 3d1efce0a437118671fc0d3b3a03df29bc4f0726 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 5 Mar 2019 12:56:53 +0100 Subject: [PATCH 19/80] LanguageClient: Fix possible crash on shutdown If a shutdown is in progress we need an immediately delete of the client to avoid accessing an already deleted TextMarkRegistry instance when deleteLater() is triggered too late. Change-Id: I274f40532cec0bfc026322a633441a1856cb848c Reviewed-by: David Schulz --- src/plugins/languageclient/languageclientmanager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 22261e62730..614617edda4 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -125,7 +125,10 @@ void LanguageClientManager::deleteClient(Client *client) QTC_ASSERT(client, return); client->disconnect(); managerInstance->m_clients.removeAll(client); - client->deleteLater(); + if (managerInstance->m_shuttingDown) + delete client; + else + client->deleteLater(); } void LanguageClientManager::shutdown() From 7cfc18276f039d70ab3a342b5037e4fde21515df Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 6 Mar 2019 09:54:02 +0100 Subject: [PATCH 20/80] ProjectExplorer: Fix Kit::setup() This function traversed the kit aspects in the wrong order, presumably based on outdated assumptions. Change-Id: I1cbb9ed74b9ef165f410b88cac3f1ca9983d1647 Reviewed-by: hjk --- src/plugins/projectexplorer/kit.cpp | 8 +++----- src/plugins/projectexplorer/kitmanager.cpp | 4 +++- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/projectexplorer/kit.cpp b/src/plugins/projectexplorer/kit.cpp index e0f3939bf35..5376f0c7661 100644 --- a/src/plugins/projectexplorer/kit.cpp +++ b/src/plugins/projectexplorer/kit.cpp @@ -269,11 +269,9 @@ void Kit::fix() void Kit::setup() { KitGuard g(this); - // Process the KitInfos in reverse order: They may only be based on other information lower in - // the stack. - QList info = KitManager::kitInformation(); - for (int i = info.count() - 1; i >= 0; --i) - info.at(i)->setup(this); + const QList info = KitManager::kitInformation(); + for (KitInformation * const ki : info) + ki->setup(this); } void Kit::upgrade() diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp index 499f1f19b45..0b6e5a8b16e 100644 --- a/src/plugins/projectexplorer/kitmanager.cpp +++ b/src/plugins/projectexplorer/kitmanager.cpp @@ -69,9 +69,11 @@ class KitManagerPrivate public: Kit *m_defaultKit = nullptr; bool m_initialized = false; - std::vector> m_informationList; std::vector> m_kitList; std::unique_ptr m_writer; + + // Sorted by priority, in descending order. + std::vector> m_informationList; }; } // namespace Internal From 177bebabea796937212ac704210fc55bd4246e2b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 6 Mar 2019 10:00:14 +0100 Subject: [PATCH 21/80] Fix qmake warning "src/shared/syntax/syntax_shared.pri:6: exists(file) requires one argument." Change-Id: Ia4151228a05cc3777d38b52bf4811647c17f4f18 Reviewed-by: Christian Stenger --- .../texteditor/texteditor_dependencies.pri | 2 +- src/shared/syntax/syntax_shared.pri | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/plugins/texteditor/texteditor_dependencies.pri b/src/plugins/texteditor/texteditor_dependencies.pri index cd58e56905a..85ccb3ded7f 100644 --- a/src/plugins/texteditor/texteditor_dependencies.pri +++ b/src/plugins/texteditor/texteditor_dependencies.pri @@ -9,7 +9,7 @@ QTC_PLUGIN_DEPENDS += \ # needed for plugins that depend on TextEditor plugin include(../../shared/syntax/syntax_shared.pri) -!isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR):!isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { INCLUDEPATH *= $${KSYNTAXHIGHLIGHTING_INCLUDE_DIR} LIBS *= -L$$KSYNTAXHIGHLIGHTING_LIB_DIR -lKF5SyntaxHighlighting diff --git a/src/shared/syntax/syntax_shared.pri b/src/shared/syntax/syntax_shared.pri index 235939d35cf..a10ae45b5cb 100644 --- a/src/shared/syntax/syntax_shared.pri +++ b/src/shared/syntax/syntax_shared.pri @@ -3,17 +3,19 @@ isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR): KSYNTAXHIGHLIGHTING_LIB_DIR=$$(KSYNTAXHIGHLIGHTING_LIB_DIR) isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR): KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) -!exists($$KSYNTAXHIGHLIGHTING_LIB_DIR) { - unset(KSYNTAXHIGHLIGHTING_LIB_DIR) - unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) -} else { - isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { - !linux: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) - else: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) - } - - !exists($$KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { - unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) +!isEmpty(KSYNTAXHIGHLIGHTING_LIB_DIR) { + !exists($$KSYNTAXHIGHLIGHTING_LIB_DIR) { unset(KSYNTAXHIGHLIGHTING_LIB_DIR) + unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + } else { + isEmpty(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + !linux: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) + else: KSYNTAXHIGHLIGHTING_INCLUDE_DIR=$$absolute_path('../../include/KF5/KSyntaxHighlighting/', $$KSYNTAXHIGHLIGHTING_LIB_DIR) + } + + !exists($$KSYNTAXHIGHLIGHTING_INCLUDE_DIR) { + unset(KSYNTAXHIGHLIGHTING_INCLUDE_DIR) + unset(KSYNTAXHIGHLIGHTING_LIB_DIR) + } } } From 1b581308be691e8a3e5d20286ab8bd573a6f05b2 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 5 Mar 2019 18:13:19 +0100 Subject: [PATCH 22/80] Nim: Remove translated string which would not be shown anyway Change-Id: Ic5773b19e6d020d8d778fc864b3adb9f8e75885a Reviewed-by: Leena Miettinen Reviewed-by: Filippo Cucchetto Reviewed-by: hjk Reviewed-by: Orgad Shaneh --- src/plugins/nim/settings/nimtoolssettingswidget.ui | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plugins/nim/settings/nimtoolssettingswidget.ui b/src/plugins/nim/settings/nimtoolssettingswidget.ui index 7322c6a8eca..28c0d1ac31d 100644 --- a/src/plugins/nim/settings/nimtoolssettingswidget.ui +++ b/src/plugins/nim/settings/nimtoolssettingswidget.ui @@ -10,9 +10,6 @@ 300 - - Form - From 776d54e4352aa873f1cab014b1b32ee105514155 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 6 Mar 2019 10:11:18 +0100 Subject: [PATCH 23/80] Remove DebuggerKitInformation::defaultValue() The defaultValue() function was a half-baked version of the setup() function and prevented that one from working properly. It does not appear that anyone relies on defaultValue() having run; in fact, this function should probably be removed from the KitInformation interface entirely and its implementations be merged into setup(). Fixes: QTCREATORBUG-21994 Change-Id: I78525df8201ebd5e1883718ea7655297c9f58eb5 Reviewed-by: hjk Reviewed-by: David Schulz --- .../debugger/debuggerkitinformation.cpp | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/plugins/debugger/debuggerkitinformation.cpp b/src/plugins/debugger/debuggerkitinformation.cpp index 426df5dfa7b..ccf6009d271 100644 --- a/src/plugins/debugger/debuggerkitinformation.cpp +++ b/src/plugins/debugger/debuggerkitinformation.cpp @@ -56,24 +56,7 @@ DebuggerKitInformation::DebuggerKitInformation() setPriority(28000); } -QVariant DebuggerKitInformation::defaultValue(const Kit *k) const -{ - const Abi toolChainAbi = ToolChainKitInformation::targetAbi(k); - const Utils::FileNameList paths = Environment::systemEnvironment().path(); - QVariant nextBestFit; - for (const DebuggerItem &item : DebuggerItemManager::debuggers()) { - for (const Abi &targetAbi : item.abis()) { - if (targetAbi.isCompatibleWith(toolChainAbi)) { - if (paths.contains(item.command())) - return item.id(); // prefer debuggers found in PATH over those found elsewhere - if (nextBestFit.isNull()) - nextBestFit = item.id(); - } - } - } - - return nextBestFit; -} +QVariant DebuggerKitInformation::defaultValue(const Kit *) const { return QVariant(); } void DebuggerKitInformation::setup(Kit *k) { From 1a63297d9bca4ee7832ee81153a8428a0a785f95 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 25 Feb 2019 19:07:19 +0100 Subject: [PATCH 24/80] Clang: Improve dependency building We want to use the cached values in the database because it is faster than to parse the the files again. Task-number: QTCREATORBUG-22035 Change-Id: I7ada7073887b1d89a06332fdb617701cb69ccd68 Reviewed-by: Ivan Donchevskii --- .../refactoringdatabaseinitializer.h | 7 +- .../clangpchmanagerbackendmain.cpp | 21 +- .../source/builddependenciesprovider.cpp | 38 ++-- .../source/builddependenciesprovider.h | 6 +- .../source/builddependenciesstorage.h | 99 ++++++--- .../builddependenciesstorageinterface.h | 15 +- .../source/builddependency.h | 13 +- .../source/builddependencycollector.cpp | 24 +- .../source/builddependencycollector.h | 8 +- .../source/clangpchmanagerbackend-source.pri | 1 - ...lectbuilddependencypreprocessorcallbacks.h | 86 ++++---- ...sedmacrosandsourcespreprocessorcallbacks.h | 3 +- .../source/modifiedtimechecker.h | 108 +++++++-- .../source/pchcreator.cpp | 21 +- .../source/pchcreator.h | 19 +- .../source/pchcreatorincludes.h | 40 ---- .../clangpchmanagerbackend/source/pchtask.h | 10 +- .../source/pchtaskgenerator.cpp | 4 +- .../source/pchtasksmerger.cpp | 4 +- .../source/sourceentry.h | 25 ++- .../source/usedmacrofilter.h | 5 +- .../source/filestatus.h | 12 +- .../source/symbolindexer.cpp | 18 +- .../source/symbolstorage.h | 20 +- .../source/symbolstorageinterface.h | 1 - .../builddependenciesprovider-test.cpp | 51 +++-- .../builddependenciesstorage-test.cpp | 110 +++++++--- .../builddependencycollector-test.cpp | 206 +++++++++--------- tests/unit/unittest/filepathstorage-test.cpp | 26 ++- .../unit/unittest/gtest-creator-printing.cpp | 18 +- tests/unit/unittest/gtest-creator-printing.h | 2 - .../unittest/mockbuilddependenciesstorage.h | 13 +- tests/unit/unittest/mocksqlitedatabase.h | 4 +- .../unit/unittest/mocksqlitewritestatement.h | 18 +- tests/unit/unittest/mocksymbolstorage.h | 3 - tests/unit/unittest/pchcreator-test.cpp | 58 +++-- tests/unit/unittest/pchtaskgenerator-test.cpp | 4 +- tests/unit/unittest/pchtasksmerger-test.cpp | 4 +- .../refactoringdatabaseinitializer-test.cpp | 25 ++- tests/unit/unittest/symbolindexer-test.cpp | 53 +---- tests/unit/unittest/symbolscollector-test.cpp | 2 +- tests/unit/unittest/symbolstorage-test.cpp | 14 -- .../unit/unittest/usedmacrocollector-test.cpp | 2 +- tests/unit/unittest/usedmacrofilter-test.cpp | 40 ++-- 44 files changed, 713 insertions(+), 548 deletions(-) delete mode 100644 src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index cce203f0d44..6bbb650af7f 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -143,6 +143,7 @@ public: const Sqlite::Column &projectPartIdColumn = table.addColumn("projectPartId", Sqlite::ColumnType::Integer); const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); table.addColumn("sourceType", Sqlite::ColumnType::Integer); + table.addColumn("pchCreationTimeStamp", Sqlite::ColumnType::Integer); table.addUniqueIndex({sourceIdColumn, projectPartIdColumn}); table.addIndex({projectPartIdColumn}); @@ -168,11 +169,11 @@ public: Sqlite::Table table; table.setUseIfNotExists(true); table.setName("fileStatuses"); - table.addColumn("sourceId", Sqlite::ColumnType::Integer, Sqlite::Contraint::PrimaryKey); + table.addColumn("sourceId", + Sqlite::ColumnType::Integer, + Sqlite::Contraint::PrimaryKey); table.addColumn("size", Sqlite::ColumnType::Integer); table.addColumn("lastModified", Sqlite::ColumnType::Integer); - table.addColumn("buildDependencyTimeStamp", Sqlite::ColumnType::Integer); - table.addColumn("isInPrecompiledHeader", Sqlite::ColumnType::Integer); table.initialize(database); } diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 89567b8d386..0bc807a03d2 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -138,12 +138,14 @@ public: ClangBackEnd::Environment &environment, Sqlite::Database &database, PchManagerServer &pchManagerServer, - ClangBackEnd::ClangPathWatcherInterface &pathWatcher) - : ProcessorManager(generatedFiles), - m_environment(environment), - m_database(database), - m_pchManagerServer(pchManagerServer), - m_pathWatcher(pathWatcher) + ClangBackEnd::ClangPathWatcherInterface &pathWatcher, + ClangBackEnd::BuildDependenciesStorageInterface &buildDependenciesStorage) + : ProcessorManager(generatedFiles) + , m_environment(environment) + , m_database(database) + , m_pchManagerServer(pchManagerServer) + , m_pathWatcher(pathWatcher) + , m_buildDependenciesStorage(buildDependenciesStorage) {} protected: @@ -152,7 +154,8 @@ protected: return std::make_unique(m_environment, m_database, *m_pchManagerServer.client(), - m_pathWatcher); + m_pathWatcher, + m_buildDependenciesStorage); } private: @@ -160,6 +163,7 @@ private: Sqlite::Database &m_database; ClangBackEnd::PchManagerServer &m_pchManagerServer; ClangBackEnd::ClangPathWatcherInterface &m_pathWatcher; + ClangBackEnd::BuildDependenciesStorageInterface &m_buildDependenciesStorage; }; struct Data // because we have a cycle dependency @@ -181,7 +185,8 @@ struct Data // because we have a cycle dependency environment, database, clangPchManagerServer, - includeWatcher}; + includeWatcher, + buildDependencyStorage}; PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; ClangBackEnd::ProgressCounter pchCreationProgressCounter{[&](int progress, int total) { executeInLoop([&] { diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp index d58da0f27c2..a2a7a813ac4 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.cpp @@ -55,19 +55,19 @@ OutputContainer setUnion(InputContainer1 &&input1, BuildDependency BuildDependenciesProvider::create(const ProjectPartContainer &projectPart) { - SourceEntries includes = createSourceEntriesFromStorage(projectPart.sourcePathIds, - projectPart.projectPartId); + auto sourcesAndProjectPart = createSourceEntriesFromStorage( + projectPart.sourcePathIds, projectPart.projectPartId); - if (!m_modifiedTimeChecker.isUpToDate(includes)) { + if (!m_modifiedTimeChecker.isUpToDate(sourcesAndProjectPart.first)) { BuildDependency buildDependency = m_generator.create(projectPart); - storeBuildDependency(buildDependency); + storeBuildDependency(buildDependency, sourcesAndProjectPart.second); return buildDependency; } - return createBuildDependencyFromStorage(std::move(includes)); - + return createBuildDependencyFromStorage( + std::move(sourcesAndProjectPart.first)); } BuildDependency BuildDependenciesProvider::createBuildDependencyFromStorage( @@ -76,7 +76,7 @@ BuildDependency BuildDependenciesProvider::createBuildDependencyFromStorage( BuildDependency buildDependency; buildDependency.usedMacros = createUsedMacrosFromStorage(includes); - buildDependency.includes = std::move(includes); + buildDependency.sources = std::move(includes); return buildDependency; } @@ -101,16 +101,19 @@ UsedMacros BuildDependenciesProvider::createUsedMacrosFromStorage(const SourceEn return usedMacros; } -SourceEntries BuildDependenciesProvider::createSourceEntriesFromStorage( - const FilePathIds &sourcePathIds, Utils::SmallStringView projectPartId) const -{ +std::pair +BuildDependenciesProvider::createSourceEntriesFromStorage( + const FilePathIds &sourcePathIds, + Utils::SmallStringView projectPartName) const { SourceEntries includes; Sqlite::DeferredTransaction transaction(m_transactionBackend); + int projectPartId = m_storage.fetchProjectPartId(projectPartName); + for (FilePathId sourcePathId : sourcePathIds) { - SourceEntries entries = m_storage.fetchDependSources(sourcePathId, - projectPartId); + SourceEntries entries = + m_storage.fetchDependSources(sourcePathId, projectPartId); SourceEntries mergedEntries = setUnion(includes, entries); includes = std::move(mergedEntries); @@ -118,15 +121,14 @@ SourceEntries BuildDependenciesProvider::createSourceEntriesFromStorage( transaction.commit(); - return includes; + return {includes, projectPartId}; } -void BuildDependenciesProvider::storeBuildDependency(const BuildDependency &buildDependency) -{ +void BuildDependenciesProvider::storeBuildDependency( + const BuildDependency &buildDependency, int projectPartId) { Sqlite::ImmediateTransaction transaction(m_transactionBackend); - - m_storage.updateSources(buildDependency.includes); - m_storage.insertFileStatuses(buildDependency.fileStatuses); + m_storage.insertOrUpdateSources(buildDependency.sources, projectPartId); + m_storage.insertOrUpdateFileStatuses(buildDependency.fileStatuses); m_storage.insertOrUpdateSourceDependencies(buildDependency.sourceDependencies); m_storage.insertOrUpdateUsedMacros(buildDependency.usedMacros); diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h index 4a89ace732a..2eb52105185 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesprovider.h @@ -55,9 +55,9 @@ public: private: BuildDependency createBuildDependencyFromStorage(SourceEntries &&includes) const; UsedMacros createUsedMacrosFromStorage(const SourceEntries &includes) const; - SourceEntries createSourceEntriesFromStorage(const FilePathIds &sourcePathIds, - Utils::SmallStringView projectPartId) const; - void storeBuildDependency(const BuildDependency &buildDependency); + std::pair createSourceEntriesFromStorage( + const FilePathIds &sourcePathIds, Utils::SmallStringView projectPartName) const; + void storeBuildDependency(const BuildDependency &buildDependency, int projectPartId); private: BuildDependenciesStorageInterface &m_storage; diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h index 324552bf996..c164e7a727f 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h @@ -53,25 +53,26 @@ public: transaction.commit(); } - void updateSources(const SourceEntries &sourceEntries) override + void insertOrUpdateSources(const SourceEntries &sourceEntries, int projectPartId) override { + deleteAllProjectPartsSourcesWithProjectPartNameStatement.write( + projectPartId); + for (const SourceEntry &entry : sourceEntries) { - updateBuildDependencyTimeStampStatement.write(static_cast(entry.lastModified), - entry.sourceId.filePathId); - updateSourceTypeStatement.write(static_cast(entry.sourceType), - entry.sourceId.filePathId); + insertOrUpdateSourceTypeStatement.write(entry.sourceId.filePathId, + projectPartId, + static_cast(entry.sourceType)); } } - void insertFileStatuses(const FileStatuses &fileStatuses) override + void insertOrUpdateFileStatuses(const FileStatuses &fileStatuses) override { - WriteStatement &statement = insertFileStatusesStatement; + WriteStatement &statement = insertOrUpdateFileStatusesStatement; for (const FileStatus &fileStatus : fileStatuses) statement.write(fileStatus.filePathId.filePathId, fileStatus.size, - fileStatus.lastModified, - fileStatus.isInPrecompiledHeader); + fileStatus.lastModified); } long long fetchLowestLastModifiedTime(FilePathId sourceId) const override @@ -85,7 +86,8 @@ public: { WriteStatement &insertStatement = insertIntoNewUsedMacrosStatement; for (const UsedMacro &usedMacro : usedMacros) - insertStatement.write(usedMacro.filePathId.filePathId, usedMacro.macroName); + insertStatement.write(usedMacro.filePathId.filePathId, + usedMacro.macroName); syncNewUsedMacrosStatement.execute(); deleteOutdatedUsedMacrosStatement.execute(); @@ -104,18 +106,23 @@ public: deleteNewSourceDependenciesStatement.execute(); } - SourceEntries fetchDependSources(FilePathId sourceId, - Utils::SmallStringView projectPartName) const override + int fetchProjectPartId(Utils::SmallStringView projectPartName) override { auto projectPartId = fetchProjectPartIdStatement.template value(projectPartName); - if (projectPartId) { - return fetchSourceDependenciesStatement.template values( - 300, - sourceId.filePathId, - projectPartId.value()); - } - return {}; + if (projectPartId) + return projectPartId.value(); + + insertProjectPartNameStatement.write(projectPartName); + + return static_cast(database.lastInsertedRowId()); + } + + SourceEntries fetchDependSources(FilePathId sourceId, int projectPartId) const override + { + return fetchSourceDependenciesStatement.template values(300, + sourceId.filePathId, + projectPartId); } UsedMacros fetchUsedMacros(FilePathId sourceId) const override @@ -123,6 +130,17 @@ public: return fetchUsedMacrosStatement.template values(128, sourceId.filePathId); } + void updatePchCreationTimeStamp( + long long pchCreationTimeStamp, + Utils::SmallStringView projectPartName) override { + Sqlite::ImmediateTransaction transaction{database}; + + updatePchCreationTimeStampStatement.write(pchCreationTimeStamp, + projectPartName); + + transaction.commit(); + } + static Utils::SmallString toJson(const Utils::SmallStringVector &strings) { QJsonDocument document; @@ -207,10 +225,11 @@ public: "INSERT INTO newSourceDependencies(sourceId, dependencySourceId) VALUES (?,?)", database }; - WriteStatement insertFileStatusesStatement{ - "INSERT OR REPLACE INTO fileStatuses(sourceId, size, lastModified, isInPrecompiledHeader) VALUES (?,?,?,?)", - database - }; + WriteStatement insertOrUpdateFileStatusesStatement{ + "INSERT INTO fileStatuses(sourceId, size, lastModified) VALUES " + "(?001,?002,?003) ON " + "CONFLICT(sourceId) DO UPDATE SET size = ?002, lastModified = ?003", + database}; WriteStatement syncNewSourceDependenciesStatement{ "INSERT INTO sourceDependencies(sourceId, dependencySourceId) SELECT sourceId, dependencySourceId FROM newSourceDependencies WHERE NOT EXISTS (SELECT sourceId FROM sourceDependencies WHERE sourceDependencies.sourceId == newSourceDependencies.sourceId AND sourceDependencies.dependencySourceId == newSourceDependencies.dependencySourceId)", database @@ -223,25 +242,37 @@ public: "DELETE FROM newSourceDependencies", database }; - WriteStatement updateBuildDependencyTimeStampStatement{ - "UPDATE fileStatuses SET buildDependencyTimeStamp = ? WHERE sourceId == ?", - database - }; - WriteStatement updateSourceTypeStatement{ - "UPDATE projectPartsSources SET sourceType = ? WHERE sourceId == ?", - database - }; + WriteStatement insertOrUpdateSourceTypeStatement{ + "INSERT INTO projectPartsSources(sourceId, projectPartId, " + "sourceType) VALUES (?001, ?002, ?003) ON CONFLICT(sourceId, " + "projectPartId) DO UPDATE SET sourceType = ?003", + database}; mutable ReadStatement fetchSourceDependenciesStatement{ - "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION SELECT dependencySourceId FROM sourceDependencies, collectedDependencies WHERE sourceDependencies.sourceId == collectedDependencies.sourceId) SELECT sourceId, buildDependencyTimeStamp, sourceType FROM collectedDependencies NATURAL JOIN projectPartsSources NATURAL JOIN fileStatuses WHERE projectPartId = ? ORDER BY sourceId", - database - }; + "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION " + "SELECT dependencySourceId FROM sourceDependencies, " + "collectedDependencies WHERE sourceDependencies.sourceId == " + "collectedDependencies.sourceId) SELECT sourceId, " + "pchCreationTimeStamp, sourceType FROM " + "collectedDependencies NATURAL JOIN projectPartsSources WHERE " + "projectPartId = ? ORDER BY " + "sourceId", + database}; mutable ReadStatement fetchProjectPartIdStatement{ "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", database }; + WriteStatement insertProjectPartNameStatement{ + "INSERT INTO projectParts(projectPartName) VALUES (?)", database}; mutable ReadStatement fetchUsedMacrosStatement{ "SELECT macroName, sourceId FROM usedMacros WHERE sourceId = ? ORDER BY sourceId, macroName", database }; + WriteStatement updatePchCreationTimeStampStatement{ + "UPDATE projectPartsSources SET pchCreationTimeStamp = ?001 WHERE " + "projectPartId = (SELECT " + "projectPartId FROM projectParts WHERE projectPartName = ?002)", + database}; + WriteStatement deleteAllProjectPartsSourcesWithProjectPartNameStatement{ + "DELETE FROM projectPartsSources WHERE projectPartId = ?", database}; }; } diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h index 445afa052f2..4edc47fce1b 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorageinterface.h @@ -33,6 +33,8 @@ #include #include +#include + namespace ClangBackEnd { class BuildDependenciesStorageInterface @@ -42,13 +44,20 @@ public: BuildDependenciesStorageInterface(const BuildDependenciesStorageInterface &) = delete; BuildDependenciesStorageInterface &operator=(const BuildDependenciesStorageInterface &) = delete; - virtual void updateSources(const SourceEntries &sourceIds) = 0; + virtual void insertOrUpdateSources(const SourceEntries &sourceIds, + int projectPartId) = 0; virtual void insertOrUpdateUsedMacros(const UsedMacros &usedMacros) = 0; - virtual void insertFileStatuses(const FileStatuses &fileStatuses) = 0; + virtual void + insertOrUpdateFileStatuses(const FileStatuses &fileStatuses) = 0; virtual void insertOrUpdateSourceDependencies(const SourceDependencies &sourceDependencies) = 0; virtual long long fetchLowestLastModifiedTime(FilePathId sourceId) const = 0; - virtual SourceEntries fetchDependSources(FilePathId sourceId, Utils::SmallStringView projectPartId) const = 0; + virtual SourceEntries fetchDependSources(FilePathId sourceId, + int projectPartId) const = 0; virtual UsedMacros fetchUsedMacros(FilePathId sourceId) const = 0; + virtual int fetchProjectPartId(Utils::SmallStringView projectPartName) = 0; + virtual void updatePchCreationTimeStamp(long long pchCreationTimeStamp, + Utils::SmallStringView projectPartName) + = 0; protected: ~BuildDependenciesStorageInterface() = default; diff --git a/src/tools/clangpchmanagerbackend/source/builddependency.h b/src/tools/clangpchmanagerbackend/source/builddependency.h index 1b649e3118d..6725254e308 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependency.h +++ b/src/tools/clangpchmanagerbackend/source/builddependency.h @@ -37,7 +37,7 @@ class BuildDependency public: void clear() { - includes.clear(); + sources.clear(); usedMacros.clear(); sourceFiles.clear(); fileStatuses.clear(); @@ -46,14 +46,15 @@ public: friend bool operator==(const BuildDependency &first, const BuildDependency &second) { - return first.includes == second.includes && first.usedMacros == second.usedMacros - && first.sourceFiles == second.sourceFiles - && first.sourceDependencies == second.sourceDependencies - && first.fileStatuses == second.fileStatuses; + return first.sources == second.sources && + first.usedMacros == second.usedMacros && + first.sourceFiles == second.sourceFiles && + first.sourceDependencies == second.sourceDependencies && + first.fileStatuses == second.fileStatuses; } public: - SourceEntries includes; + SourceEntries sources; UsedMacros usedMacros; FilePathIds sourceFiles; SourceDependencies sourceDependencies; diff --git a/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp b/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp index b3ebbc75ad7..1d08442c517 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp +++ b/src/tools/clangpchmanagerbackend/source/builddependencycollector.cpp @@ -45,8 +45,27 @@ FilePathIds operator+(const FilePathIds &first, const FilePathIds &second) return result; } + +FilePaths operator+(FilePaths &&first, FilePaths &&second) { + FilePaths result = std::move(first); + + std::copy(second.begin(), second.end(), std::back_inserter(result)); + + return result; } +FilePaths generatedFilePaths(const V2::FileContainers &containers) { + FilePaths paths; + paths.reserve(containers.size()); + std::transform(containers.begin(), + containers.end(), + std::back_inserter(paths), + [](const auto &container) { return container.filePath; }); + return paths; +} + +} // namespace + BuildDependency BuildDependencyCollector::create(const ProjectPartContainer &projectPart) { CommandLineBuilder @@ -54,8 +73,9 @@ BuildDependency BuildDependencyCollector::create(const ProjectPartContainer &pro addFiles(projectPart.sourcePathIds, std::move(builder.commandLine)); - setExcludedFilePaths( - m_filePathCache.filePaths(projectPart.headerPathIds + projectPart.sourcePathIds)); + setExcludedFilePaths(m_filePathCache.filePaths(projectPart.headerPathIds + + projectPart.sourcePathIds) + + generatedFilePaths(m_generatedFiles.fileContainers())); addUnsavedFiles(m_generatedFiles.fileContainers()); diff --git a/src/tools/clangpchmanagerbackend/source/builddependencycollector.h b/src/tools/clangpchmanagerbackend/source/builddependencycollector.h index c5e41e91907..f8aaa8f07cd 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependencycollector.h +++ b/src/tools/clangpchmanagerbackend/source/builddependencycollector.h @@ -83,11 +83,11 @@ public: return m_buildDependency.sourceDependencies; } - const SourceEntries &includeIds() - { - std::sort(m_buildDependency.includes.begin(), m_buildDependency.includes.end()); + const SourceEntries &sourceEntries() { + std::sort(m_buildDependency.sources.begin(), + m_buildDependency.sources.end()); - return std::move(m_buildDependency.includes); + return std::move(m_buildDependency.sources); } private: diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri index 94d9540beae..fa8d6e527a6 100644 --- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri +++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri @@ -9,7 +9,6 @@ SOURCES += \ $$PWD/pchtaskqueue.cpp HEADERS += \ - $$PWD/pchcreatorincludes.h \ $$PWD/pchmanagerserver.h \ $$PWD/clangpchmanagerbackend_global.h \ $$PWD/pchnotcreatederror.h \ diff --git a/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h index 980d065fdbc..658c51cb1a3 100644 --- a/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h @@ -109,36 +109,46 @@ public: clang::SrcMgr::CharacteristicKind fileType) override { clang::FileID currentFileId = m_sourceManager->getFileID(hashLocation); - if (file && currentFileId != m_mainFileId) { - addSourceDependency(file, hashLocation); - auto fileUID = file->getUID(); - auto sourceFileUID = m_sourceManager - ->getFileEntryForID(m_sourceManager->getFileID(hashLocation)) - ->getUID(); - auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); - if (notAlreadyIncluded.first) { - m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, fileUID); - FilePath filePath = filePathFromFile(file); - if (!filePath.empty()) { - FilePathId includeId = m_filePathCache.filePathId(filePath); + if (file) { + if (currentFileId != m_mainFileId) { + addSourceDependency(file, hashLocation); + auto fileUID = file->getUID(); + auto sourceFileUID = + m_sourceManager + ->getFileEntryForID( + m_sourceManager->getFileID(hashLocation)) + ->getUID(); + auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); + if (notAlreadyIncluded.first) { + m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, + fileUID); + FilePath filePath = filePathFromFile(file); + if (!filePath.empty()) { + FilePathId includeId = + m_filePathCache.filePathId(filePath); - time_t lastModified = file->getModificationTime(); + time_t lastModified = file->getModificationTime(); - SourceType sourceType = SourceType::UserInclude; - if (isSystem(fileType)) { - if (isInSystemHeader(hashLocation)) - sourceType = SourceType::SystemInclude; - else - sourceType = SourceType::TopSystemInclude; - } else if (isNotInExcludedIncludeUID(fileUID)) { - if (isInExcludedIncludeUID(sourceFileUID)) - sourceType = SourceType::TopProjectInclude; - else - sourceType = SourceType::ProjectInclude; + SourceType sourceType = SourceType::UserInclude; + if (isSystem(fileType)) { + if (isInSystemHeader(hashLocation)) + sourceType = SourceType::SystemInclude; + else + sourceType = SourceType::TopSystemInclude; + } else if (isNotInExcludedIncludeUID(fileUID)) { + if (isInExcludedIncludeUID(sourceFileUID)) + sourceType = SourceType::TopProjectInclude; + else + sourceType = SourceType::ProjectInclude; + } + + addSource({includeId, sourceType, lastModified}); } - - addInclude({includeId, sourceType, lastModified}); } + } else { + addSource({m_filePathCache.filePathId(filePathFromFile(file)), + SourceType::Source, + file->getModificationTime()}); } } else { auto sourceFileId = filePathId(hashLocation); @@ -270,7 +280,7 @@ public: } }; - auto &includes = m_buildDependency.includes; + auto &includes = m_buildDependency.sources; SourceEntries newIncludes; newIncludes.reserve(includes.size()); std::set_difference(includes.begin(), @@ -280,7 +290,7 @@ public: std::back_inserter(newIncludes), Compare{}); - m_buildDependency.includes = newIncludes; + m_buildDependency.sources = newIncludes; } SourceDependencies sourceDependenciesSortedByDependendFilePathId() const @@ -296,7 +306,7 @@ public: void filterOutIncludesWithMissingIncludes() { - sortAndMakeUnique(m_containsMissingIncludes);; + sortAndMakeUnique(m_containsMissingIncludes); collectSourceWithMissingIncludes(m_containsMissingIncludes, sourceDependenciesSortedByDependendFilePathId()); @@ -339,16 +349,16 @@ public: return FilePath::fromNativeFilePath(absolutePath(file->getName())); } - void addInclude(SourceEntry sourceEntry) - { - auto &includes = m_buildDependency.includes; - auto found = std::lower_bound(includes.begin(), - includes.end(), - sourceEntry, - [](auto first, auto second) { return first < second; }); + void addSource(SourceEntry sourceEntry) { + auto &sources = m_buildDependency.sources; + auto found = std::lower_bound( + sources.begin(), + sources.end(), + sourceEntry, + [](auto first, auto second) { return first < second; }); - if (found == includes.end() || *found != sourceEntry) - includes.emplace(found, sourceEntry); + if (found == sources.end() || *found != sourceEntry) + sources.emplace(found, sourceEntry); } private: diff --git a/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h index 90108bd76b1..b8ea406df0f 100644 --- a/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectusedmacrosandsourcespreprocessorcallbacks.h @@ -92,8 +92,7 @@ public: m_fileStatuses.emplace(found, id, fileEntry->getSize(), - fileEntry->getModificationTime(), - fileEntry->isInPCH()); + fileEntry->getModificationTime()); } } diff --git a/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h b/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h index 88d5f140d53..d641de054cb 100644 --- a/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h +++ b/src/tools/clangpchmanagerbackend/source/modifiedtimechecker.h @@ -75,21 +75,68 @@ public: private: bool compareEntries(const SourceEntries &sourceEntries) const { + class CompareSourceId + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + }; + SourceTimeStamps currentSourceTimeStamp; currentSourceTimeStamp.reserve(sourceEntries.size()); std::set_intersection(m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), sourceEntries.begin(), sourceEntries.end(), - std::back_inserter(currentSourceTimeStamp)); + std::back_inserter(currentSourceTimeStamp), + CompareSourceId{}); - return std::equal(currentSourceTimeStamp.begin(), - currentSourceTimeStamp.end(), - sourceEntries.begin(), - sourceEntries.end(), - [](SourceTimeStamp first, SourceTimeStamp second) { - return first.lastModified <= second.lastModified; - }); + class CompareTime + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) + { + return first.lastModified <= second.lastModified; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.pchCreationTimeStamp <= + second.pchCreationTimeStamp; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.lastModified <= second.pchCreationTimeStamp; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.pchCreationTimeStamp <= second.lastModified; + } + }; + + return std::lexicographical_compare(currentSourceTimeStamp.begin(), + currentSourceTimeStamp.end(), + sourceEntries.begin(), + sourceEntries.end(), + CompareTime{}); } void updateCurrentSourceTimeStamps(const SourceEntries &sourceEntries) const @@ -102,8 +149,8 @@ private: } auto split = sourceTimeStamps.insert(sourceTimeStamps.end(), - m_currentSourceTimeStamps.begin(), - m_currentSourceTimeStamps.end()); + m_currentSourceTimeStamps.begin(), + m_currentSourceTimeStamps.end()); std::inplace_merge(sourceTimeStamps.begin(), split, sourceTimeStamps.end()); m_currentSourceTimeStamps = sourceTimeStamps; @@ -111,14 +158,49 @@ private: SourceTimeStamps newSourceTimeStamps(const SourceEntries &sourceEntries) const { - SourceTimeStamps newTimeStamps; - newTimeStamps.reserve(sourceEntries.size() + m_currentSourceTimeStamps.size()); + SourceEntries newSourceEntries; + newSourceEntries.reserve(sourceEntries.size()); + + class CompareSourceId + { + public: + bool operator()(SourceTimeStamp first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceTimeStamp first, SourceEntry second) + { + return first.sourceId < second.sourceId; + } + + bool operator()(SourceEntry first, SourceTimeStamp second) + { + return first.sourceId < second.sourceId; + } + }; std::set_difference(sourceEntries.begin(), sourceEntries.end(), m_currentSourceTimeStamps.begin(), m_currentSourceTimeStamps.end(), - std::back_inserter(newTimeStamps)); + std::back_inserter(newSourceEntries), + CompareSourceId{}); + + SourceTimeStamps newTimeStamps; + newTimeStamps.reserve(newSourceEntries.size()); + + std::transform(newSourceEntries.begin(), + newSourceEntries.end(), + std::back_inserter(newTimeStamps), + [](SourceEntry entry) { + return SourceTimeStamp{entry.sourceId, {}}; + }); return newTimeStamps; } diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index b8227ce9645..3f858b50ee3 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -31,6 +31,7 @@ #include "generatepchactionfactory.h" #include "pchnotcreatederror.h" +#include #include #include #include @@ -110,7 +111,7 @@ Utils::SmallStringVector PchCreator::generateClangCompilerArguments(const PchTas void PchCreator::generatePch(PchTask &&pchTask) { - long long lastModified = QDateTime::currentSecsSinceEpoch(); + m_projectPartPch.lastModified = QDateTime::currentSecsSinceEpoch(); auto content = generatePchIncludeFileContent(pchTask.includes); auto pchOutputPath = generatePchFilePath(); @@ -123,9 +124,8 @@ void PchCreator::generatePch(PchTask &&pchTask) m_projectPartPch.projectPartId = pchTask.projectPartId(); if (success) { - m_allInclues = pchTask.allIncludes; + m_sources = pchTask.sources; m_projectPartPch.pchPath = std::move(pchOutputPath); - m_projectPartPch.lastModified = lastModified; } } @@ -163,18 +163,21 @@ void PchCreator::clear() { m_clangTool = ClangTool{}; m_projectPartPch = {}; + m_sources.clear(); } void PchCreator::doInMainThreadAfterFinished() { - FilePathIds existingIncludes; - existingIncludes.reserve(m_allInclues.size()); - std::set_difference(m_allInclues.begin(), - m_allInclues.end(), + FilePathIds existingSources; + existingSources.reserve(m_sources.size()); + std::set_difference(m_sources.begin(), + m_sources.end(), m_generatedFilePathIds.begin(), m_generatedFilePathIds.end(), - std::back_inserter(existingIncludes)); - m_clangPathwatcher.updateIdPaths({{m_projectPartPch.projectPartId, existingIncludes}}); + std::back_inserter(existingSources)); + m_buildDependenciesStorage.updatePchCreationTimeStamp(m_projectPartPch.lastModified, + m_projectPartPch.projectPartId); + m_clangPathwatcher.updateIdPaths({{m_projectPartPch.projectPartId, existingSources}}); m_pchManagerClient.precompiledHeadersUpdated(ProjectPartPchs{m_projectPartPch}); } diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.h b/src/tools/clangpchmanagerbackend/source/pchcreator.h index 73f185176d7..f1fadcd33a9 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.h @@ -27,7 +27,6 @@ #include "pchcreatorinterface.h" -#include "pchcreatorincludes.h" #include "idpaths.h" #include "sourceentry.h" #include "clangtool.h" @@ -49,6 +48,7 @@ class Environment; class GeneratedFiles; class PchManagerClientInterface; class ClangPathWatcherInterface; +class BuildDependenciesStorageInterface; class PchCreator final : public PchCreatorInterface { @@ -56,12 +56,12 @@ public: PchCreator(Environment &environment, Sqlite::Database &database, PchManagerClientInterface &pchManagerClient, - ClangPathWatcherInterface &clangPathwatcher) - : m_filePathCache(database) - , m_environment(environment) - , m_pchManagerClient(pchManagerClient) - , m_clangPathwatcher(clangPathwatcher) - {} + ClangPathWatcherInterface &clangPathwatcher, + BuildDependenciesStorageInterface &buildDependenciesStorage) + : m_filePathCache(database), m_environment(environment), + m_pchManagerClient(pchManagerClient), + m_clangPathwatcher(clangPathwatcher), + m_buildDependenciesStorage(buildDependenciesStorage) {} void generatePch(PchTask &&pchTask) override; const ProjectPartPch &projectPartPch() override; @@ -85,16 +85,19 @@ public: return m_clangTool; } + const FilePathIds &sources() const { return m_sources; } + private: mutable std::mt19937_64 randomNumberGenator{std::random_device{}()}; ClangTool m_clangTool; ProjectPartPch m_projectPartPch; FilePathCaching m_filePathCache; - FilePathIds m_allInclues; + FilePathIds m_sources; FilePathIds m_generatedFilePathIds; Environment &m_environment; PchManagerClientInterface &m_pchManagerClient; ClangPathWatcherInterface &m_clangPathwatcher; + BuildDependenciesStorageInterface &m_buildDependenciesStorage; bool m_isUsed = false; }; diff --git a/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h b/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h deleted file mode 100644 index 6854c599070..00000000000 --- a/src/tools/clangpchmanagerbackend/source/pchcreatorincludes.h +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include - -namespace ClangBackEnd { - -class PchCreatorIncludes -{ -public: - FilePathIds includeIds; - FilePathIds topIncludeIds; - FilePathIds topSystemIncludeIds; -}; - -} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchtask.h b/src/tools/clangpchmanagerbackend/source/pchtask.h index c94d7ac8164..528d6e63f13 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtask.h +++ b/src/tools/clangpchmanagerbackend/source/pchtask.h @@ -41,7 +41,7 @@ class PchTask public: PchTask(Utils::SmallString &&projectPartId, FilePathIds &&includes, - FilePathIds &&allIncludes, + FilePathIds &&sources, CompilerMacros &&compilerMacros, Utils::SmallStringVector &&usedMacros, Utils::SmallStringVector toolChainArguments, @@ -52,7 +52,7 @@ public: Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None) : projectPartIds({projectPartId}) , includes(includes) - , allIncludes(allIncludes) + , sources(sources) , compilerMacros(compilerMacros) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) @@ -64,7 +64,7 @@ public: PchTask(Utils::SmallStringVector &&projectPartIds, FilePathIds &&includes, - FilePathIds &&allIncludes, + FilePathIds &&sources, CompilerMacros &&compilerMacros, Utils::SmallStringVector &&usedMacros, Utils::SmallStringVector toolChainArguments, @@ -75,7 +75,7 @@ public: Utils::LanguageExtension languageExtension = Utils::LanguageExtension::None) : projectPartIds(std::move(projectPartIds)) , includes(includes) - , allIncludes(allIncludes) + , sources(sources) , compilerMacros(compilerMacros) , systemIncludeSearchPaths(std::move(systemIncludeSearchPaths)) , projectIncludeSearchPaths(std::move(projectIncludeSearchPaths)) @@ -104,7 +104,7 @@ public: FilePath systemPchPath; Utils::SmallStringVector projectPartIds; FilePathIds includes; - FilePathIds allIncludes; + FilePathIds sources; CompilerMacros compilerMacros; IncludeSearchPaths systemIncludeSearchPaths; IncludeSearchPaths projectIncludeSearchPaths; diff --git a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp index aab3bfe7d48..a44fc91b168 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtaskgenerator.cpp @@ -45,7 +45,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, for (auto &projectPart : projectParts) { BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart); - UsedMacroFilter filter{buildDependency.includes, + UsedMacroFilter filter{buildDependency.sources, buildDependency.usedMacros, projectPart.compilerMacros}; @@ -62,7 +62,7 @@ void PchTaskGenerator::addProjectParts(ProjectPartContainers &&projectParts, projectPart.languageExtension}, PchTask{std::move(projectPart.projectPartId), std::move(filter.topProjectIncludes), - std::move(filter.allIncludes), + std::move(filter.sources), std::move(filter.projectCompilerMacros), std::move(filter.projectUsedMacros), projectPart.toolChainArguments, diff --git a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp index 50851a838a0..65d1a3e9fed 100644 --- a/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchtasksmerger.cpp @@ -96,8 +96,8 @@ bool PchTasksMerger::mergePchTasks(PchTask &firstTask, PchTask &secondTask) firstTask.projectPartIds = merge(std::move(firstTask.projectPartIds), std::move(secondTask.projectPartIds)); firstTask.includes = merge(std::move(firstTask.includes), std::move(secondTask.includes)); - firstTask.allIncludes = merge(std::move(firstTask.allIncludes), - std::move(secondTask.allIncludes)); + firstTask.sources = merge(std::move(firstTask.sources), + std::move(secondTask.sources)); firstTask.compilerMacros = std::move(macros); firstTask.systemIncludeSearchPaths = mergeIncludeSearchPaths( std::move(firstTask.systemIncludeSearchPaths), diff --git a/src/tools/clangpchmanagerbackend/source/sourceentry.h b/src/tools/clangpchmanagerbackend/source/sourceentry.h index e903baf3f6b..d5bb28d904f 100644 --- a/src/tools/clangpchmanagerbackend/source/sourceentry.h +++ b/src/tools/clangpchmanagerbackend/source/sourceentry.h @@ -31,19 +31,20 @@ namespace ClangBackEnd { -enum class SourceType : unsigned char -{ +enum class SourceType : unsigned char { TopProjectInclude, TopSystemInclude, UserInclude, ProjectInclude, - SystemInclude + SystemInclude, + Source }; class TimeStamp { using int64 = long long; public: + TimeStamp() = default; TimeStamp(int64 value) : value(value) {} @@ -58,7 +59,6 @@ public: class SourceTimeStamp { -protected: using int64 = long long; public: SourceTimeStamp(int sourceId, int64 lastModified) @@ -103,17 +103,20 @@ public: using SourceTimeStamps = std::vector; -class SourceEntry : public SourceTimeStamp +class SourceEntry { + using int64 = long long; public: - SourceEntry(int sourceId, int64 lastModified, int sourceType) - : SourceTimeStamp(sourceId, lastModified) + SourceEntry(int sourceId, int64 pchCreationTimeStamp, int sourceType) + : pchCreationTimeStamp(pchCreationTimeStamp) + , sourceId(sourceId) , sourceType(static_cast(sourceType)) {} - SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp lastModified) - : SourceTimeStamp(sourceId, lastModified) + SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp pchCreationTimeStamp) + : pchCreationTimeStamp(pchCreationTimeStamp) + , sourceId(sourceId) , sourceType(sourceType) {} @@ -125,12 +128,14 @@ public: friend bool operator==(SourceEntry first, SourceEntry second) { return first.sourceId == second.sourceId && first.sourceType == second.sourceType - && first.lastModified == second.lastModified; + && first.pchCreationTimeStamp == second.pchCreationTimeStamp; } friend bool operator!=(SourceEntry first, SourceEntry second) { return !(first == second); } public: + TimeStamp pchCreationTimeStamp; + FilePathId sourceId; SourceType sourceType = SourceType::UserInclude; }; diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index 6042895325a..bd9788e61cb 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -139,10 +139,11 @@ private: projectIncludes.emplace_back(include.sourceId); break; case SourceType::UserInclude: + case SourceType::Source: break; } - allIncludes.emplace_back(include.sourceId); + sources.emplace_back(include.sourceId); } static Utils::SmallStringVector filterUsedMarcos(const UsedMacros &usedMacros, @@ -209,7 +210,7 @@ private: } public: - FilePathIds allIncludes; + FilePathIds sources; FilePathIds projectIncludes; FilePathIds systemIncludes; FilePathIds topProjectIncludes; diff --git a/src/tools/clangrefactoringbackend/source/filestatus.h b/src/tools/clangrefactoringbackend/source/filestatus.h index 9ade5462948..da2be4a304e 100644 --- a/src/tools/clangrefactoringbackend/source/filestatus.h +++ b/src/tools/clangrefactoringbackend/source/filestatus.h @@ -36,15 +36,8 @@ namespace ClangBackEnd { class FileStatus { public: - FileStatus(FilePathId filePathId, - off_t size, - std::time_t lastModified, - bool isInPrecompiledHeader) - : filePathId(filePathId), - size(size), - lastModified(lastModified), - isInPrecompiledHeader(isInPrecompiledHeader) - {} + FileStatus(FilePathId filePathId, off_t size, std::time_t lastModified) + : filePathId(filePathId), size(size), lastModified(lastModified) {} friend bool operator==(const FileStatus &first, const FileStatus &second) @@ -64,7 +57,6 @@ public: FilePathId filePathId; off_t size; std::time_t lastModified; - bool isInPrecompiledHeader; }; using FileStatuses = std::vector; diff --git a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp index 6928e497125..aee8344fc90 100644 --- a/src/tools/clangrefactoringbackend/source/symbolindexer.cpp +++ b/src/tools/clangrefactoringbackend/source/symbolindexer.cpp @@ -120,8 +120,7 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) std::vector symbolIndexerTask; symbolIndexerTask.reserve(projectPart.sourcePathIds.size()); for (FilePathId sourcePathId : projectPart.sourcePathIds) { - auto indexing = [projectPartId, - arguments = commandLineBuilder.commandLine, + auto indexing = [arguments = commandLineBuilder.commandLine, sourcePathId, this](SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(sourcePathId, arguments); @@ -134,12 +133,9 @@ void SymbolIndexer::updateProjectPart(ProjectPartContainer &&projectPart) m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), symbolsCollector.sourceLocations()); - m_symbolStorage.updateProjectPartSources(projectPartId, - symbolsCollector.sourceFiles()); - m_buildDependencyStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_buildDependencyStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_buildDependencyStorage.insertOrUpdateFileStatuses(symbolsCollector.fileStatuses()); m_buildDependencyStorage.insertOrUpdateSourceDependencies( symbolsCollector.sourceDependencies()); @@ -193,10 +189,8 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, CommandLineBuilder builder{artefact, artefact.toolChainArguments, InputFileType::Source, {}, {}, pchPath}; - auto indexing = [projectPartId = artefact.projectPartId, - arguments = builder.commandLine, - filePathId, - this](SymbolsCollectorInterface &symbolsCollector) { + auto indexing = [arguments = builder.commandLine, filePathId, this]( + SymbolsCollectorInterface &symbolsCollector) { symbolsCollector.setFile(filePathId, arguments); bool success = symbolsCollector.collectSymbols(); @@ -207,11 +201,9 @@ void SymbolIndexer::updateChangedPath(FilePathId filePathId, m_symbolStorage.addSymbolsAndSourceLocations(symbolsCollector.symbols(), symbolsCollector.sourceLocations()); - m_symbolStorage.updateProjectPartSources(projectPartId, symbolsCollector.sourceFiles()); - m_buildDependencyStorage.insertOrUpdateUsedMacros(symbolsCollector.usedMacros()); - m_buildDependencyStorage.insertFileStatuses(symbolsCollector.fileStatuses()); + m_buildDependencyStorage.insertOrUpdateFileStatuses(symbolsCollector.fileStatuses()); m_buildDependencyStorage.insertOrUpdateSourceDependencies( symbolsCollector.sourceDependencies()); diff --git a/src/tools/clangrefactoringbackend/source/symbolstorage.h b/src/tools/clangrefactoringbackend/source/symbolstorage.h index 3b7141c7838..798fa26dd06 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorage.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorage.h @@ -112,17 +112,6 @@ public: return statement.template value(projectPartName); } - void updateProjectPartSources(int projectPartId, - const FilePathIds &sourceFilePathIds) override - { - WriteStatement &deleteStatement = m_deleteAllProjectPartsSourcesWithProjectPartIdStatement; - deleteStatement.write(projectPartId); - - WriteStatement &insertStatement = m_insertProjectPartSourcesStatement; - for (const FilePathId &sourceFilePathId : sourceFilePathIds) - insertStatement.write(projectPartId, sourceFilePathId.filePathId); - } - static Utils::SmallString toJson(const Utils::SmallStringVector &strings) { QJsonDocument document; @@ -322,14 +311,7 @@ public: "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", m_database }; - WriteStatement m_deleteAllProjectPartsSourcesWithProjectPartIdStatement{ - "DELETE FROM projectPartsSources WHERE projectPartId = ?", - m_database - }; - WriteStatement m_insertProjectPartSourcesStatement{ - "INSERT INTO projectPartsSources(projectPartId, sourceId) VALUES (?,?)", - m_database - }; + mutable ReadStatement m_getCompileArgumentsForFileIdStatement{ "SELECT toolChainArguments FROM projectParts WHERE projectPartId = (SELECT projectPartId " "FROM projectPartsSources WHERE sourceId = ?)", diff --git a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h index 5f2e6c30e68..210f66f7da1 100644 --- a/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h +++ b/src/tools/clangrefactoringbackend/source/symbolstorageinterface.h @@ -61,7 +61,6 @@ public: Utils::LanguageVersion languageVersion, Utils::LanguageExtension languageExtension) = 0; - virtual void updateProjectPartSources(int projectPartId, const FilePathIds &sourceFilePathIds) = 0; virtual Utils::optional fetchProjectPartArtefact( FilePathId sourceId) const = 0; virtual Utils::optional fetchProjectPartArtefact( diff --git a/tests/unit/unittest/builddependenciesprovider-test.cpp b/tests/unit/unittest/builddependenciesprovider-test.cpp index 2a5372c55dc..b69965cc56f 100644 --- a/tests/unit/unittest/builddependenciesprovider-test.cpp +++ b/tests/unit/unittest/builddependenciesprovider-test.cpp @@ -99,9 +99,7 @@ protected: UsedMacros thirdUsedMacros{{"SAN", 10}}; FilePathIds sourceFiles{1, 3, 8}; ClangBackEnd::SourceDependencies sourceDependencies{{1, 3}, {1, 8}}; - ClangBackEnd::FileStatuses fileStatuses{{1, 21, 12, false}, - {3, 21, 12, false}, - {8, 21, 12, false}}; + ClangBackEnd::FileStatuses fileStatuses{{1, 21, 12}, {3, 21, 12}, {8, 21, 12}}; BuildDependency buildDependency{ secondSources, secondUsedMacros, @@ -117,7 +115,9 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromStorageIfTime EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); EXPECT_CALL(mockBuildDependenciesStorage, - fetchDependSources({2}, TypedEq("ProjectPart1"))) + fetchProjectPartId(TypedEq("ProjectPart1"))) + .WillOnce(Return(11)); + EXPECT_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)) .WillRepeatedly(Return(firstSources)); EXPECT_CALL(mockSqliteTransactionBackend, commit()); EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(firstSources)).WillRepeatedly(Return(true)); @@ -132,15 +132,24 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromStorageIfTime TEST_F(BuildDependenciesProvider, FetchDependSourcesFromStorage) { - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq("ProjectPart2"))).WillByDefault(Return(firstSources)); - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({3}, TypedEq("ProjectPart2"))).WillByDefault(Return(secondSources)); - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({4}, TypedEq("ProjectPart2"))).WillByDefault(Return(thirdSources)); + ON_CALL(mockBuildDependenciesStorage, + fetchProjectPartId(TypedEq("ProjectPart2"))) + .WillByDefault(Return(11)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)).WillByDefault(Return(firstSources)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({3}, 11)).WillByDefault(Return(secondSources)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({4}, 11)).WillByDefault(Return(thirdSources)); ON_CALL(mockModifiedTimeChecker, isUpToDate(_)).WillByDefault(Return(true)); auto buildDependency = provider.create(projectPart2); - ASSERT_THAT(buildDependency.includes, ElementsAre(HasSourceId(1), HasSourceId(2), HasSourceId(3), HasSourceId(4), HasSourceId(8), HasSourceId(10))); + ASSERT_THAT(buildDependency.sources, + ElementsAre(HasSourceId(1), + HasSourceId(2), + HasSourceId(3), + HasSourceId(4), + HasSourceId(8), + HasSourceId(10))); } TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromGeneratorIfTimeStampsAreNotUpToDate) @@ -149,15 +158,17 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromGeneratorIfTi EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); EXPECT_CALL(mockBuildDependenciesStorage, - fetchDependSources({2}, TypedEq("ProjectPart1"))) + fetchProjectPartId(TypedEq("ProjectPart1"))) + .WillOnce(Return(11)); + EXPECT_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq(11))) .WillRepeatedly(Return(firstSources)); EXPECT_CALL(mockSqliteTransactionBackend, commit()); EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(firstSources)).WillRepeatedly(Return(false)); EXPECT_CALL(mockBuildDependenciesGenerator, create(projectPart1)) .WillOnce(Return(buildDependency)); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); - EXPECT_CALL(mockBuildDependenciesStorage, updateSources(Eq(secondSources))); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatuses))); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSources(Eq(secondSources), 11)); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatuses))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(secondUsedMacros))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); @@ -167,13 +178,16 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchDependSourcesFromGeneratorIfTi TEST_F(BuildDependenciesProvider, FetchDependSourcesFromGenerator) { - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq("ProjectPart1"))).WillByDefault(Return(firstSources)); + ON_CALL(mockBuildDependenciesStorage, + fetchProjectPartId(TypedEq("ProjectPart1"))) + .WillByDefault(Return(11)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)).WillByDefault(Return(firstSources)); ON_CALL(mockModifiedTimeChecker, isUpToDate(_)).WillByDefault(Return(false)); ON_CALL(mockBuildDependenciesGenerator, create(projectPart1)).WillByDefault(Return(buildDependency)); auto buildDependency = provider.create(projectPart1); - ASSERT_THAT(buildDependency.includes, ElementsAre(HasSourceId(1), HasSourceId(3), HasSourceId(8))); + ASSERT_THAT(buildDependency.sources, ElementsAre(HasSourceId(1), HasSourceId(3), HasSourceId(8))); } TEST_F(BuildDependenciesProvider, CreateCallsFetchUsedMacrosFromStorageIfTimeStampsAreUpToDate) @@ -181,7 +195,11 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchUsedMacrosFromStorageIfTimeSta InSequence s; EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); - EXPECT_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq("ProjectPart1"))).WillRepeatedly(Return(firstSources)); + EXPECT_CALL(mockBuildDependenciesStorage, + fetchProjectPartId(TypedEq("ProjectPart1"))) + .WillOnce(Return(11)); + EXPECT_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)) + .WillRepeatedly(Return(firstSources)); EXPECT_CALL(mockSqliteTransactionBackend, commit()); EXPECT_CALL(mockModifiedTimeChecker, isUpToDate(firstSources)).WillRepeatedly(Return(true)); EXPECT_CALL(mockSqliteTransactionBackend, deferredBegin()); @@ -195,7 +213,10 @@ TEST_F(BuildDependenciesProvider, CreateCallsFetchUsedMacrosFromStorageIfTimeSta TEST_F(BuildDependenciesProvider, FetchUsedMacrosFromStorageIfDependSourcesAreUpToDate) { - ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, TypedEq("ProjectPart1"))).WillByDefault(Return(firstSources)); + ON_CALL(mockBuildDependenciesStorage, + fetchProjectPartId(TypedEq("ProjectPart1"))) + .WillByDefault(Return(11)); + ON_CALL(mockBuildDependenciesStorage, fetchDependSources({2}, 11)).WillByDefault(Return(firstSources)); ON_CALL(mockModifiedTimeChecker, isUpToDate(firstSources)).WillByDefault(Return(true)); ON_CALL(mockBuildDependenciesStorage, fetchUsedMacros({1})).WillByDefault(Return(firstUsedMacros)); ON_CALL(mockBuildDependenciesStorage, fetchUsedMacros({2})).WillByDefault(Return(secondUsedMacros)); diff --git a/tests/unit/unittest/builddependenciesstorage-test.cpp b/tests/unit/unittest/builddependenciesstorage-test.cpp index d69f8b868a2..8112107e2b5 100644 --- a/tests/unit/unittest/builddependenciesstorage-test.cpp +++ b/tests/unit/unittest/builddependenciesstorage-test.cpp @@ -55,17 +55,20 @@ protected: MockSqliteWriteStatement &syncNewUsedMacrosStatement =storage.syncNewUsedMacrosStatement; MockSqliteWriteStatement &deleteOutdatedUsedMacrosStatement = storage.deleteOutdatedUsedMacrosStatement; MockSqliteWriteStatement &deleteNewUsedMacrosTableStatement = storage.deleteNewUsedMacrosTableStatement; - MockSqliteWriteStatement &insertFileStatuses = storage.insertFileStatusesStatement; + MockSqliteWriteStatement &insertOrUpdateFileStatusesStatement = storage.insertOrUpdateFileStatusesStatement; MockSqliteWriteStatement &insertIntoNewSourceDependenciesStatement = storage.insertIntoNewSourceDependenciesStatement; MockSqliteWriteStatement &syncNewSourceDependenciesStatement = storage.syncNewSourceDependenciesStatement; MockSqliteWriteStatement &deleteOutdatedSourceDependenciesStatement = storage.deleteOutdatedSourceDependenciesStatement; MockSqliteWriteStatement &deleteNewSourceDependenciesStatement = storage.deleteNewSourceDependenciesStatement; MockSqliteReadStatement &getLowestLastModifiedTimeOfDependencies = storage.getLowestLastModifiedTimeOfDependencies; - MockSqliteWriteStatement &updateBuildDependencyTimeStampStatement = storage.updateBuildDependencyTimeStampStatement; - MockSqliteWriteStatement &updateSourceTypeStatement = storage.updateSourceTypeStatement; + MockSqliteWriteStatement &insertOrUpdateSourceTypeStatement = storage.insertOrUpdateSourceTypeStatement; MockSqliteReadStatement &fetchSourceDependenciesStatement = storage.fetchSourceDependenciesStatement; MockSqliteReadStatement &fetchProjectPartIdStatement = storage.fetchProjectPartIdStatement; MockSqliteReadStatement &fetchUsedMacrosStatement = storage.fetchUsedMacrosStatement; + MockSqliteWriteStatement &insertProjectPartNameStatement = storage.insertProjectPartNameStatement; + MockSqliteWriteStatement &updatePchCreationTimeStampStatement = storage.updatePchCreationTimeStampStatement; + MockSqliteWriteStatement &deleteAllProjectPartsSourcesWithProjectPartNameStatement + = storage.deleteAllProjectPartsSourcesWithProjectPartNameStatement; }; TEST_F(BuildDependenciesStorage, ConvertStringsToJson) @@ -81,8 +84,10 @@ TEST_F(BuildDependenciesStorage, InsertOrUpdateUsedMacros) { InSequence sequence; - EXPECT_CALL(insertIntoNewUsedMacrosStatement, write(TypedEq(42u), TypedEq("FOO"))); - EXPECT_CALL(insertIntoNewUsedMacrosStatement, write(TypedEq(43u), TypedEq("BAR"))); + EXPECT_CALL(insertIntoNewUsedMacrosStatement, + write(TypedEq(42), TypedEq("FOO"))); + EXPECT_CALL(insertIntoNewUsedMacrosStatement, + write(TypedEq(43), TypedEq("BAR"))); EXPECT_CALL(syncNewUsedMacrosStatement, execute()); EXPECT_CALL(deleteOutdatedUsedMacrosStatement, execute()); EXPECT_CALL(deleteNewUsedMacrosTableStatement, execute()); @@ -90,12 +95,14 @@ TEST_F(BuildDependenciesStorage, InsertOrUpdateUsedMacros) storage.insertOrUpdateUsedMacros({{"FOO", 42}, {"BAR", 43}}); } -TEST_F(BuildDependenciesStorage, InsertFileStatuses) +TEST_F(BuildDependenciesStorage, InsertOrUpdateFileStatuses) { - EXPECT_CALL(insertFileStatuses, write(TypedEq(42), TypedEq(1), TypedEq(2), TypedEq(false))); - EXPECT_CALL(insertFileStatuses, write(TypedEq(43), TypedEq(4), TypedEq(5), TypedEq(true))); + EXPECT_CALL(insertOrUpdateFileStatusesStatement, + write(TypedEq(42), TypedEq(1), TypedEq(2))); + EXPECT_CALL(insertOrUpdateFileStatusesStatement, + write(TypedEq(43), TypedEq(4), TypedEq(5))); - storage.insertFileStatuses({{42, 1, 2, false}, {43, 4, 5, true}}); + storage.insertOrUpdateFileStatuses({{42, 1, 2}, {43, 4, 5}}); } TEST_F(BuildDependenciesStorage, InsertOrUpdateSourceDependencies) @@ -125,7 +132,6 @@ TEST_F(BuildDependenciesStorage, AddTablesInConstructor) Storage storage{mockDatabase}; } - TEST_F(BuildDependenciesStorage, FetchLowestLastModifiedTimeIfNoModificationTimeExists) { EXPECT_CALL(getLowestLastModifiedTimeOfDependencies, valueReturnInt64(Eq(1))); @@ -168,48 +174,82 @@ TEST_F(BuildDependenciesStorage, AddNewSourceDependenciesTable) TEST_F(BuildDependenciesStorage, UpdateSources) { InSequence s; - SourceEntries entries{{1, SourceType::TopProjectInclude, 10}, {2, SourceType::TopSystemInclude, 20}}; + SourceEntries entries{{1, SourceType::TopProjectInclude, 10}, + {2, SourceType::TopSystemInclude, 20}}; - EXPECT_CALL(updateBuildDependencyTimeStampStatement, write(TypedEq(10), TypedEq(1))); - EXPECT_CALL(updateSourceTypeStatement, write(TypedEq(0), TypedEq(1))); - EXPECT_CALL(updateBuildDependencyTimeStampStatement, write(TypedEq(20), TypedEq(2))); - EXPECT_CALL(updateSourceTypeStatement, write(TypedEq(1), TypedEq(2))); + EXPECT_CALL(deleteAllProjectPartsSourcesWithProjectPartNameStatement, write(TypedEq(22))); + EXPECT_CALL(insertOrUpdateSourceTypeStatement, + write(TypedEq(1), TypedEq(22), TypedEq(0))); + EXPECT_CALL(insertOrUpdateSourceTypeStatement, + write(TypedEq(2), TypedEq(22), TypedEq(1))); - storage.updateSources(entries); + storage.insertOrUpdateSources(entries, 22); } -TEST_F(BuildDependenciesStorage, CallsFetchDependSourcesWithNonExistingProjectPartDontFetchesSourceDependencies) +TEST_F(BuildDependenciesStorage, UpdatePchCreationTimeStamp) { - EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq("test"))).WillOnce(Return(Utils::optional{})); - EXPECT_CALL(fetchSourceDependenciesStatement, valuesReturnSourceEntries(_, _, _)).Times(0); + InSequence s; - storage.fetchDependSources(22, "test"); + EXPECT_CALL(mockDatabase, immediateBegin()); + EXPECT_CALL(updatePchCreationTimeStampStatement, + write(TypedEq(101), TypedEq("project1"))); + EXPECT_CALL(mockDatabase, commit()); + + storage.updatePchCreationTimeStamp(101, "project1"); } -TEST_F(BuildDependenciesStorage, CallsFetchDependSourcesWithExistingProjectPartFetchesSourceDependencies) +TEST_F(BuildDependenciesStorage, CallsFetchProjectIdWithNonExistingProjectPartName) +{ + EXPECT_CALL(fetchProjectPartIdStatement, + valueReturnInt32(TypedEq("test"))); + EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq("test"))); + + storage.fetchProjectPartId("test"); +} + +TEST_F(BuildDependenciesStorage, CallsFetchProjectIdWithExistingProjectPart) +{ + EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq("test"))) + .WillOnce(Return(Utils::optional{20})); + EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq("test"))).Times(0); + + storage.fetchProjectPartId("test"); +} + +TEST_F(BuildDependenciesStorage, FetchProjectIdWithNonExistingProjectPartName) +{ + ON_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq("test"))) + .WillByDefault(Return(Utils::optional{})); + ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(21)); + + int id = storage.fetchProjectPartId("test"); + + ASSERT_THAT(id, 21); +} + +TEST_F(BuildDependenciesStorage, FetchProjectIdWithExistingProjectPartName) +{ + ON_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq("test"))) + .WillByDefault(Return(Utils::optional{20})); + + int id = storage.fetchProjectPartId("test"); + + ASSERT_THAT(id, 20); +} + +TEST_F(BuildDependenciesStorage, CallsFetchDependSources) { - EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq("test"))).WillOnce(Return(Utils::optional{20})); EXPECT_CALL(fetchSourceDependenciesStatement, valuesReturnSourceEntries(_, 22, 20)); - storage.fetchDependSources(22, "test"); + storage.fetchDependSources(22, 20); } -TEST_F(BuildDependenciesStorage, FetchDependSourcesWithNonExistingProjectPartReturnsEmptySourceEntries) -{ - EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq("test"))).WillOnce(Return(Utils::optional{})); - - auto entries = storage.fetchDependSources(22, "test"); - - ASSERT_THAT(entries, IsEmpty()); -} - -TEST_F(BuildDependenciesStorage, FetchDependSourcesWithExistingProjectPartReturnsSourceEntries) +TEST_F(BuildDependenciesStorage, FetchDependSources) { SourceEntries sourceEntries{{1, SourceType::TopProjectInclude, 10}, {2, SourceType::TopSystemInclude, 20}}; - EXPECT_CALL(fetchProjectPartIdStatement, valueReturnInt32(TypedEq("test"))).WillOnce(Return(Utils::optional{20})); EXPECT_CALL(fetchSourceDependenciesStatement, valuesReturnSourceEntries(_, 22, 20)).WillOnce(Return(sourceEntries)); - auto entries = storage.fetchDependSources(22, "test"); + auto entries = storage.fetchDependSources(22, 20); ASSERT_THAT(entries, sourceEntries); } diff --git a/tests/unit/unittest/builddependencycollector-test.cpp b/tests/unit/unittest/builddependencycollector-test.cpp index aa46fc77bb1..d8965c0a9f8 100644 --- a/tests/unit/unittest/builddependencycollector-test.cpp +++ b/tests/unit/unittest/builddependencycollector-test.cpp @@ -53,7 +53,9 @@ using ClangBackEnd::UsedMacro; namespace { -MATCHER_P2(HasInclude, sourceId, sourceType, +MATCHER_P2(HasSource, + sourceId, + sourceType, std::string(negation ? "hasn't " : "has ") + PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType, -1))) { @@ -107,50 +109,50 @@ protected: ClangBackEnd::FileStatus fileStatus(Utils::SmallStringView filePath) const { - return {id(filePath), fileSize(filePath), lastModified(filePath), false}; + return {id(filePath), fileSize(filePath), lastModified(filePath)}; } - static FilePathIds filteredIncludes(const ClangBackEnd::SourceEntries &includes, - ClangBackEnd::SourceType includeType) + static FilePathIds filteredSources(const ClangBackEnd::SourceEntries &sources, + ClangBackEnd::SourceType sourceType) { - FilePathIds filteredIncludes; + FilePathIds filteredSources; - for (const ClangBackEnd::SourceEntry &include : includes) { - if (include.sourceType == includeType) - filteredIncludes.push_back(include.sourceId); + for (const ClangBackEnd::SourceEntry &source : sources) { + if (source.sourceType == sourceType) + filteredSources.push_back(source.sourceId); } - return filteredIncludes; + return filteredSources; } - static FilePathIds topIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds topSources(const ClangBackEnd::SourceEntries &sources) { - return filteredIncludes(includes, ClangBackEnd::SourceType::TopProjectInclude); + return filteredSources(sources, ClangBackEnd::SourceType::TopProjectInclude); } - static FilePathIds systemTopIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds systemTopSources(const ClangBackEnd::SourceEntries &sources) { - return filteredIncludes(includes, ClangBackEnd::SourceType::TopSystemInclude); + return filteredSources(sources, ClangBackEnd::SourceType::TopSystemInclude); } - static FilePathIds userIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds userSources(const ClangBackEnd::SourceEntries &sources) { - return filteredIncludes(includes, ClangBackEnd::SourceType::UserInclude); + return filteredSources(sources, ClangBackEnd::SourceType::UserInclude); } - static FilePathIds projectPartIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds projectPartSources(const ClangBackEnd::SourceEntries &sources) { - return filteredIncludes(includes, ClangBackEnd::SourceType::ProjectInclude); + return filteredSources(sources, ClangBackEnd::SourceType::ProjectInclude); } - static FilePathIds allIncludes(const ClangBackEnd::SourceEntries &includes) + static FilePathIds sources(const ClangBackEnd::SourceEntries &sources) { - FilePathIds filteredIncludes; + FilePathIds filteredSources; - for (const ClangBackEnd::SourceEntry &include : includes) - filteredIncludes.push_back(include.sourceId); + for (const ClangBackEnd::SourceEntry &source : sources) + filteredSources.push_back(source.sourceId); - return filteredIncludes; + return filteredSources; } protected: @@ -173,26 +175,30 @@ TEST_F(BuildDependencyCollector, IncludesExternalHeader) { collector.collect(); - ASSERT_THAT(allIncludes(collector.includeIds()), + ASSERT_THAT(sources(collector.sourceEntries()), AllOf(Contains(id(TESTDATA_DIR "/builddependencycollector/external/external1.h")), Contains(id(TESTDATA_DIR "/builddependencycollector/external/external2.h")), - Contains(id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h")), - Contains(id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h")))); + Contains(id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external.h")), + Contains(id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external2.h")))); } TEST_F(BuildDependencyCollector, InternalHeaderAreUserIncludes) { collector.collect(); - ASSERT_THAT(userIncludes(collector.includeIds()), Contains(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"))); + ASSERT_THAT(userSources(collector.sourceEntries()), + Contains(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"))); } TEST_F(BuildDependencyCollector, NoDuplicate) { collector.collect(); - ASSERT_THAT(allIncludes(collector.includeIds()), + ASSERT_THAT(sources(collector.sourceEntries()), UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), @@ -206,15 +212,17 @@ TEST_F(BuildDependencyCollector, IncludesAreSorted) { collector.collect(); - ASSERT_THAT(allIncludes(collector.includeIds()), - ElementsAre( - id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"), - id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))); + ASSERT_THAT(sources(collector.sourceEntries()), + ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), + id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external.h"), + id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))); } TEST_F(BuildDependencyCollector, If) @@ -223,8 +231,9 @@ TEST_F(BuildDependencyCollector, If) emptyCollector.collect(); - ASSERT_THAT(allIncludes(emptyCollector.includeIds()), - ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/true.h"))); + ASSERT_THAT(sources(emptyCollector.sourceEntries()), + ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/if.cpp"), + id(TESTDATA_DIR "/builddependencycollector/project/true.h"))); } TEST_F(BuildDependencyCollector, LocalPath) @@ -233,8 +242,9 @@ TEST_F(BuildDependencyCollector, LocalPath) emptyCollector.collect(); - ASSERT_THAT(allIncludes(emptyCollector.includeIds()), + ASSERT_THAT(sources(emptyCollector.sourceEntries()), UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), @@ -250,20 +260,22 @@ TEST_F(BuildDependencyCollector, IgnoreMissingFile) emptyCollector.collect(); - ASSERT_THAT(allIncludes(emptyCollector.includeIds()), - UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"), - id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"))); + ASSERT_THAT(sources(emptyCollector.sourceEntries()), + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"), + id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"))); } TEST_F(BuildDependencyCollector, IncludesOnlyTopExternalHeader) { collector.collect(); - ASSERT_THAT(topIncludes(collector.includeIds()), - UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external3.h"))); + ASSERT_THAT( + topSources(collector.sourceEntries()), + UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external3.h"))); } TEST_F(BuildDependencyCollector, TopIncludeInIfMacro) @@ -273,7 +285,7 @@ TEST_F(BuildDependencyCollector, TopIncludeInIfMacro) emptyCollector.collect(); - ASSERT_THAT(topIncludes(emptyCollector.includeIds()), + ASSERT_THAT(topSources(emptyCollector.sourceEntries()), ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/true.h"))); } @@ -283,10 +295,11 @@ TEST_F(BuildDependencyCollector, TopIncludeWithLocalPath) emptyCollector.collect(); - ASSERT_THAT(topIncludes(emptyCollector.includeIds()), - UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external3.h"))); + ASSERT_THAT( + topSources(emptyCollector.sourceEntries()), + UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external3.h"))); } TEST_F(BuildDependencyCollector, TopIncludesIgnoreMissingFile) @@ -296,8 +309,9 @@ TEST_F(BuildDependencyCollector, TopIncludesIgnoreMissingFile) emptyCollector.collect(); - ASSERT_THAT(topIncludes(emptyCollector.includeIds()), - UnorderedElementsAre(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"))); + ASSERT_THAT(topSources(emptyCollector.sourceEntries()), + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/external/external1.h"))); } TEST_F(BuildDependencyCollector, SourceFiles) @@ -620,10 +634,10 @@ TEST_F(BuildDependencyCollector, MissingInclude) emptyCollector.collect(); - ASSERT_THAT(emptyCollector.includeIds(), + ASSERT_THAT(emptyCollector.sourceEntries(), ElementsAre( - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - SourceType::UserInclude))); + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + SourceType::UserInclude))); } @@ -643,10 +657,12 @@ TEST_F(BuildDependencyCollector, GeneratedFile) emptyCollector.collect(); - ASSERT_THAT(emptyCollector.includeIds(), - ElementsAre( - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), - SourceType::UserInclude))); + ASSERT_THAT( + emptyCollector.sourceEntries(), + ElementsAre(HasSource(id(TESTDATA_DIR "/builddependencycollector/project/main6.cpp"), + SourceType::Source), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), + SourceType::UserInclude))); } TEST_F(BuildDependencyCollector, CreateFakeFileContent) @@ -715,41 +731,37 @@ TEST_F(BuildDependencyCollector, Create) fileStatus(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"), fileStatus(TESTDATA_DIR "/builddependencycollector/project/macros.h"), ClangBackEnd::FileStatus( - id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), - 12, - 0, - false))), - Field(&BuildDependency::includes, - UnorderedElementsAre( - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - SourceType::UserInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), - SourceType::UserInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), - SourceType::TopProjectInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - SourceType::TopProjectInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/external/indirect_external.h"), - SourceType::ProjectInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/external/indirect_external2.h"), - SourceType::ProjectInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), - SourceType::TopProjectInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), - SourceType::TopSystemInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/system/indirect_system.h"), - SourceType::SystemInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/system/indirect_system2.h"), - SourceType::SystemInclude), - HasInclude(id(TESTDATA_DIR "/builddependencycollector/project/macros.h"), - SourceType::UserInclude), - HasInclude(id(TESTDATA_DIR - "/builddependencycollector/project/generated_file.h"), - SourceType::TopProjectInclude))), + id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), 12, 0))), + Field( + &BuildDependency::sources, + UnorderedElementsAre( + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + SourceType::UserInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + SourceType::UserInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), + SourceType::TopProjectInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + SourceType::TopProjectInclude), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external.h"), + SourceType::ProjectInclude), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/external/indirect_external2.h"), + SourceType::ProjectInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + SourceType::TopProjectInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/system/system1.h"), + SourceType::TopSystemInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/system/indirect_system.h"), + SourceType::SystemInclude), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/system/indirect_system2.h"), + SourceType::SystemInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/macros.h"), + SourceType::UserInclude), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/generated_file.h"), + SourceType::UserInclude))), Field(&BuildDependency::usedMacros, UnorderedElementsAre( UsedMacro{"IFDEF", id(TESTDATA_DIR "/builddependencycollector/project/macros.h")}, @@ -843,6 +855,6 @@ TEST_F(BuildDependencyCollector, Clear) auto buildDependency = collector.create(projectPart); - ASSERT_THAT(buildDependency.includes, IsEmpty()); + ASSERT_THAT(buildDependency.sources, IsEmpty()); } } // namespace diff --git a/tests/unit/unittest/filepathstorage-test.cpp b/tests/unit/unittest/filepathstorage-test.cpp index be689b44f32..c08c84e9132 100644 --- a/tests/unit/unittest/filepathstorage-test.cpp +++ b/tests/unit/unittest/filepathstorage-test.cpp @@ -189,7 +189,8 @@ TEST_F(FilePathStorage, CallWriteForWriteDirectory) TEST_F(FilePathStorage, CallWriteForWriteSource) { - EXPECT_CALL(insertIntoSources, write(5, TypedEq("unknownfile.h"))); + EXPECT_CALL(insertIntoSources, + write(TypedEq(5), TypedEq("unknownfile.h"))); storage.writeSourceId(5, "unknownfile.h"); } @@ -280,7 +281,8 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceIdForUnknownEntry) EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("unknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq("unknownfile.h"))); + EXPECT_CALL(insertIntoSources, + write(TypedEq(5), TypedEq("unknownfile.h"))); EXPECT_CALL(mockDatabase, commit()); storage.fetchSourceId(5, "unknownfile.h"); @@ -347,7 +349,8 @@ TEST_F(FilePathStorage, RestartFetchSourceIdIfTheDatabaseIsBusyInBeginBecauseThe EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq("otherunknownfile.h"))); + EXPECT_CALL(insertIntoSources, + write(TypedEq(5), TypedEq("otherunknownfile.h"))); EXPECT_CALL(mockDatabase, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); @@ -360,13 +363,16 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheDatabase EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq("otherunknownfile.h"))) - .WillOnce(Throw(Sqlite::StatementIsBusy("busy")));; + EXPECT_CALL(insertIntoSources, + write(TypedEq(5), TypedEq("otherunknownfile.h"))) + .WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + ; EXPECT_CALL(mockDatabase, rollback()); EXPECT_CALL(mockDatabase, deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq("otherunknownfile.h"))); + EXPECT_CALL(insertIntoSources, + write(TypedEq(5), TypedEq("otherunknownfile.h"))); EXPECT_CALL(mockDatabase, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); @@ -379,12 +385,14 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingSourceTwoTimesIfTheIndexIsC EXPECT_CALL(mockDatabase,deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(5, Eq("otherunknownfile.h"))); - EXPECT_CALL(insertIntoSources, write(5, TypedEq("otherunknownfile.h"))) - .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy")));; + EXPECT_CALL(insertIntoSources, + write(TypedEq(5), TypedEq("otherunknownfile.h"))) + .WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy"))); EXPECT_CALL(mockDatabase, rollback()); EXPECT_CALL(mockDatabase,deferredBegin()); EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, - valueReturnInt32(5, Eq("otherunknownfile.h"))); + valueReturnInt32(5, Eq("otherunknownfile.h"))) + .WillOnce(Return(Utils::optional(42))); EXPECT_CALL(mockDatabase, commit()); storage.fetchSourceId(5, "otherunknownfile.h"); diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 60f5e526cb6..63dde52dc21 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -45,7 +45,6 @@ #include #include #include -#include #include #include #include @@ -1151,11 +1150,6 @@ std::ostream &operator<<(std::ostream &out, const ProgressMessage &message) << message.total << ")"; } -std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes) -{ - return out << "(" << includes.includeIds << ", " << includes.topIncludeIds << ", " - << includes.topSystemIncludeIds << ")"; -} std::ostream &operator<<(std::ostream &out, const PchTask &task) { return out << "(" << task.projectPartIds << ", " << task.includes << ", " << task.compilerMacros @@ -1172,11 +1166,11 @@ std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet) std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency) { return out << "(\n" - << "includes: " << dependency.includes << ",\n" - << "usedMacros: " << dependency.usedMacros << ",\n" - << "fileStatuses: " << dependency.fileStatuses << ",\n" - << "sourceFiles: " << dependency.sourceFiles << ",\n" - << "sourceDependencies: " << dependency.sourceDependencies << ",\n" + << "includes: " << dependency.sources << ",\n" + << "usedMacros: " << dependency.usedMacros << ",\n" + << "fileStatuses: " << dependency.fileStatuses << ",\n" + << "sourceFiles: " << dependency.sourceFiles << ",\n" + << "sourceDependencies: " << dependency.sourceDependencies << ",\n" << ")"; } @@ -1200,6 +1194,8 @@ const char *sourceTypeString(SourceType sourceType) return "ProjectInclude"; case SourceType::UserInclude: return "UserInclude"; + case SourceType::Source: + return "Source"; } return ""; diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h index cb63fd56bb9..75eae281ae4 100644 --- a/tests/unit/unittest/gtest-creator-printing.h +++ b/tests/unit/unittest/gtest-creator-printing.h @@ -186,7 +186,6 @@ class SuspendResumeJobsEntry; class ReferencesResult; class SymbolIndexerTask; class ProgressMessage; -class PchCreatorIncludes; class PchTask; class PchTaskSet; class BuildDependency; @@ -277,7 +276,6 @@ std::ostream &operator<<(std::ostream &os, const SuspendResumeJobsEntry &entry); std::ostream &operator<<(std::ostream &os, const ReferencesResult &value); std::ostream &operator<<(std::ostream &out, const SymbolIndexerTask &task); std::ostream &operator<<(std::ostream &out, const ProgressMessage &message); -std::ostream &operator<<(std::ostream &out, const PchCreatorIncludes &includes); std::ostream &operator<<(std::ostream &out, const PchTask &task); std::ostream &operator<<(std::ostream &out, const PchTaskSet &taskSet); std::ostream &operator<<(std::ostream &out, const BuildDependency &dependency); diff --git a/tests/unit/unittest/mockbuilddependenciesstorage.h b/tests/unit/unittest/mockbuilddependenciesstorage.h index a654579a831..739c13cf8da 100644 --- a/tests/unit/unittest/mockbuilddependenciesstorage.h +++ b/tests/unit/unittest/mockbuilddependenciesstorage.h @@ -32,19 +32,22 @@ class MockBuildDependenciesStorage : public ClangBackEnd::BuildDependenciesStorageInterface { public: - MOCK_METHOD1(updateSources, - void (const ClangBackEnd::SourceEntries &sources)); + MOCK_METHOD2(insertOrUpdateSources, + void(const ClangBackEnd::SourceEntries &sources, int projectPartId)); MOCK_METHOD1(insertOrUpdateUsedMacros, void (const ClangBackEnd::UsedMacros &usedMacros)); - MOCK_METHOD1(insertFileStatuses, - void (const ClangBackEnd::FileStatuses &fileStatuses)); + MOCK_METHOD1(insertOrUpdateFileStatuses, void(const ClangBackEnd::FileStatuses &fileStatuses)); MOCK_METHOD1(insertOrUpdateSourceDependencies, void (const ClangBackEnd::SourceDependencies &sourceDependencies)); MOCK_CONST_METHOD1(fetchLowestLastModifiedTime, long long (ClangBackEnd::FilePathId sourceId)); MOCK_CONST_METHOD2(fetchDependSources, - ClangBackEnd::SourceEntries (ClangBackEnd::FilePathId sourceId, Utils::SmallStringView)); + ClangBackEnd::SourceEntries(ClangBackEnd::FilePathId sourceId, + int projectPartId)); MOCK_CONST_METHOD1(fetchUsedMacros, ClangBackEnd::UsedMacros (ClangBackEnd::FilePathId sourceId)); + MOCK_METHOD1(fetchProjectPartId, int(Utils::SmallStringView projectPartName)); + MOCK_METHOD2(updatePchCreationTimeStamp, + void(long long pchCreationTimeStamp, Utils::SmallStringView projectPartName)); }; diff --git a/tests/unit/unittest/mocksqlitedatabase.h b/tests/unit/unittest/mocksqlitedatabase.h index 0b890e01f0a..5bef2ba8c51 100644 --- a/tests/unit/unittest/mocksqlitedatabase.h +++ b/tests/unit/unittest/mocksqlitedatabase.h @@ -39,8 +39,8 @@ class MockSqliteDatabase : public MockSqliteTransactionBackend { public: - using ReadStatement = MockSqliteReadStatement; - using WriteStatement = MockSqliteWriteStatement; + using ReadStatement = NiceMock; + using WriteStatement = NiceMock; MOCK_METHOD1(execute, void (Utils::SmallStringView sqlStatement)); diff --git a/tests/unit/unittest/mocksqlitewritestatement.h b/tests/unit/unittest/mocksqlitewritestatement.h index ee7df6362f7..edaea7d7e18 100644 --- a/tests/unit/unittest/mocksqlitewritestatement.h +++ b/tests/unit/unittest/mocksqlitewritestatement.h @@ -42,8 +42,7 @@ public: MOCK_METHOD0(execute, void ()); - MOCK_METHOD2(bind, - void (int index, Utils::SmallStringView value)); + MOCK_METHOD2(bind, void(int, Utils::SmallStringView)); MOCK_METHOD2(bindValues, void (Utils::SmallStringView, Utils::SmallStringView)); @@ -60,11 +59,11 @@ public: MOCK_METHOD5(write, void (long long, int, int, int, int)); - MOCK_METHOD2(write, - void (uint, Utils::SmallStringView)); + MOCK_METHOD2(write, void(uint, Utils::SmallStringView)); - MOCK_METHOD2(write, - void (Utils::SmallStringView, Utils::SmallStringView)); + MOCK_METHOD2(write, void(int, Utils::SmallStringView)); + + MOCK_METHOD2(write, void(Utils::SmallStringView, Utils::SmallStringView)); MOCK_METHOD3(write, void (Utils::SmallStringView, Utils::SmallStringView, long long)); @@ -103,17 +102,16 @@ public: MOCK_METHOD3(write, void (uint, uint, uint)); - MOCK_METHOD4(write, - void (int, off_t, time_t, bool)); + MOCK_METHOD3(write, void(int, off_t, time_t)); MOCK_METHOD2(write, void (uint, uint)); MOCK_METHOD2(write, void (uchar, int)); - + MOCK_METHOD3(write, void(int, int, uchar)); MOCK_METHOD2(write, void (long long, int)); - + MOCK_METHOD2(write, void(long long, Utils::SmallStringView)); Utils::SmallString sqlStatement; }; diff --git a/tests/unit/unittest/mocksymbolstorage.h b/tests/unit/unittest/mocksymbolstorage.h index 325e18b1c97..c4b55fcfe41 100644 --- a/tests/unit/unittest/mocksymbolstorage.h +++ b/tests/unit/unittest/mocksymbolstorage.h @@ -46,9 +46,6 @@ public: Utils::Language language, Utils::LanguageVersion languageVersion, Utils::LanguageExtension languageExtension)); - MOCK_METHOD2(updateProjectPartSources, - void(int projectPartId, - const ClangBackEnd::FilePathIds &sourceFilePathIds)); MOCK_CONST_METHOD1(fetchProjectPartArtefact, Utils::optional (ClangBackEnd::FilePathId sourceId)); MOCK_CONST_METHOD1(fetchProjectPartArtefact, diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index d891a089871..b28769b51bb 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -28,6 +28,7 @@ #include "fakeprocess.h" #include "filesystem-utilities.h" +#include "mockbuilddependenciesstorage.h" #include "mockclangpathwatcher.h" #include "mockpchmanagerclient.h" #include "testenvironment.h" @@ -97,16 +98,22 @@ protected: FileContainer generatedFile{generatedFilePath.clone(), "#pragma once", {}}; NiceMock mockPchManagerClient; NiceMock mockClangPathWatcher; - ClangBackEnd::PchCreator creator{environment, database, mockPchManagerClient, mockClangPathWatcher}; + NiceMock mockBuildDependenciesStorage; + ClangBackEnd::PchCreator creator{environment, + database, + mockPchManagerClient, + mockClangPathWatcher, + mockBuildDependenciesStorage}; PchTask pchTask1{ "project1", {id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), id(TESTDATA_DIR "/builddependencycollector/external/external2.h")}, - {id(generatedFilePath), - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + {id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h")}, + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + id(generatedFilePath), + id(main2Path)}, {}, {}, {}, @@ -190,25 +197,24 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchsSendToPchManagerClient) creator.doInMainThreadAfterFinished(); } -TEST_F(PchCreatorVerySlowTest, AllIncludesAreWatchedAfterSucess) +TEST_F(PchCreatorVerySlowTest, SourcesAreWatchedAfterSucess) { creator.generatePch(std::move(pchTask1)); - EXPECT_CALL( - mockClangPathWatcher, - updateIdPaths(ElementsAre( - AllOf(Field(&ClangBackEnd::IdPaths::id, "project1"), - Field(&ClangBackEnd::IdPaths::filePathIds, - UnorderedElementsAre( - id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), - id(TESTDATA_DIR "/builddependencycollector/external/external2.h"))))))); + EXPECT_CALL(mockClangPathWatcher, + updateIdPaths(ElementsAre(AllOf( + Field(&ClangBackEnd::IdPaths::id, "project1"), + Field(&ClangBackEnd::IdPaths::filePathIds, + UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), + id(TESTDATA_DIR "/builddependencycollector/external/external2.h"), + id(TESTDATA_DIR "/builddependencycollector/project/main2.cpp"))))))); creator.doInMainThreadAfterFinished(); } - -TEST_F(PchCreatorVerySlowTest, AllIncludesAreNotWatchedAfterFail) +TEST_F(PchCreatorVerySlowTest, SourcesAreNotWatchedAfterFail) { pchTask1.systemIncludeSearchPaths = {}; pchTask1.projectIncludeSearchPaths = {}; @@ -222,6 +228,15 @@ TEST_F(PchCreatorVerySlowTest, AllIncludesAreNotWatchedAfterFail) creator.doInMainThreadAfterFinished(); } +TEST_F(PchCreatorVerySlowTest, PchCreationTimeStampsAreUpdated) +{ + creator.generatePch(std::move(pchTask1)); + + EXPECT_CALL(mockBuildDependenciesStorage, updatePchCreationTimeStamp(_, Eq("project1"))); + + creator.doInMainThreadAfterFinished(); +} + TEST_F(PchCreatorVerySlowTest, ProjectPartPchForCreatesPchForPchTask) { creator.generatePch(std::move(pchTask1)); @@ -241,6 +256,15 @@ TEST_F(PchCreatorVerySlowTest, ProjectPartPchCleared) ASSERT_THAT(creator.projectPartPch(), ClangBackEnd::ProjectPartPch{}); } +TEST_F(PchCreatorVerySlowTest, SourcesCleared) +{ + creator.generatePch(std::move(pchTask1)); + + creator.clear(); + + ASSERT_THAT(creator.sources(), IsEmpty()); +} + TEST_F(PchCreatorVerySlowTest, ClangToolCleared) { creator.generatePch(std::move(pchTask1)); @@ -266,7 +290,7 @@ TEST_F(PchCreatorVerySlowTest, FaultyProjectPartPchForCreatesFaultyPchForPchTask ASSERT_THAT(creator.projectPartPch(), AllOf(Field(&ProjectPartPch::projectPartId, Eq("faultyProjectPart")), Field(&ProjectPartPch::pchPath, IsEmpty()), - Field(&ProjectPartPch::lastModified, Eq(-1)))); + Field(&ProjectPartPch::lastModified, Gt(0)))); } TEST_F(PchCreatorVerySlowTest, GeneratedFile) diff --git a/tests/unit/unittest/pchtaskgenerator-test.cpp b/tests/unit/unittest/pchtaskgenerator-test.cpp index d85432baf25..a6946f7ccff 100644 --- a/tests/unit/unittest/pchtaskgenerator-test.cpp +++ b/tests/unit/unittest/pchtaskgenerator-test.cpp @@ -99,7 +99,7 @@ TEST_F(PchTaskGenerator, AddProjectParts) Field(&PchTaskSet::system, AllOf(Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")), Field(&PchTask::includes, ElementsAre(5)), - Field(&PchTask::allIncludes, IsEmpty()), + Field(&PchTask::sources, IsEmpty()), Field(&PchTask::compilerMacros, ElementsAre(CompilerMacro{"SE", "4", 4}, CompilerMacro{"WU", "5", 5})), Field(&PchTask::systemIncludeSearchPaths, @@ -116,7 +116,7 @@ TEST_F(PchTaskGenerator, AddProjectParts) &PchTaskSet::project, AllOf(Field(&PchTask::projectPartIds, ElementsAre("ProjectPart1")), Field(&PchTask::includes, ElementsAre(3)), - Field(&PchTask::allIncludes, ElementsAre(1, 2, 3, 4, 5)), + Field(&PchTask::sources, ElementsAre(1, 2, 3, 4, 5)), Field(&PchTask::compilerMacros, ElementsAre(CompilerMacro{"YI", "1", 1}, CompilerMacro{"SAN", "3", 3})), Field(&PchTask::systemIncludeSearchPaths, diff --git a/tests/unit/unittest/pchtasksmerger-test.cpp b/tests/unit/unittest/pchtasksmerger-test.cpp index c279da505e7..da61d14adbd 100644 --- a/tests/unit/unittest/pchtasksmerger-test.cpp +++ b/tests/unit/unittest/pchtasksmerger-test.cpp @@ -272,14 +272,14 @@ TEST_F(PchTasksMerger, MergeAllIncludes) { Merger::mergePchTasks(systemTask1, systemTask2); - ASSERT_THAT(systemTask1.allIncludes, ElementsAre(1, 2, 3, 11, 12, 13)); + ASSERT_THAT(systemTask1.sources, ElementsAre(1, 2, 3, 11, 12, 13)); } TEST_F(PchTasksMerger, DontAllMergeIncludes) { Merger::mergePchTasks(systemTask1, systemTask3); - ASSERT_THAT(systemTask1.allIncludes, ElementsAre(1, 2, 3)); + ASSERT_THAT(systemTask1.sources, ElementsAre(1, 2, 3)); } TEST_F(PchTasksMerger, MergeProjectIds) diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp index 7e1e730b179..34eaec10bdd 100644 --- a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -102,7 +102,9 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsSourcesTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, sourceId INTEGER, sourceType INTEGER)"))); + EXPECT_CALL(mockDatabase, + execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " + "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON projectPartsSources(projectPartId)"))); @@ -124,7 +126,11 @@ TEST_F(RefactoringDatabaseInitializer, AddFileStatusesTable) { InSequence s; - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, lastModified INTEGER, buildDependencyTimeStamp INTEGER, isInPrecompiledHeader INTEGER)"))); + EXPECT_CALL( + mockDatabase, + execute(Eq( + "CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, " + "lastModified INTEGER)"))); initializer.createFileStatusesTable(); } @@ -171,13 +177,19 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor) "TEXT, systemIncludeSearchPaths TEXT, projectIncludeSearchPaths TEXT, " "language INTEGER, languageVersion INTEGER, languageExtension INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, sourceId INTEGER, sourceType INTEGER)"))); + EXPECT_CALL(mockDatabase, + execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " + "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON projectPartsSources(projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, lastModified INTEGER, buildDependencyTimeStamp INTEGER, isInPrecompiledHeader INTEGER)"))); + EXPECT_CALL( + mockDatabase, + execute(Eq( + "CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, " + "lastModified INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, projectPchPath TEXT, projectPchBuildTime INTEGER, systemPchPath TEXT, systemPchBuildTime INTEGER)"))); @@ -215,7 +227,10 @@ TEST_F(RefactoringDatabaseInitializer, DontCreateIfAlreadyInitialized) EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))).Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_sourceId_macroName ON usedMacros(sourceId, macroName)"))).Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_usedMacros_macroName ON usedMacros(macroName)"))).Times(0); - EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, size INTEGER, lastModified INTEGER, isInPrecompiledHeader INTEGER)"))).Times(0); + EXPECT_CALL(mockDatabase, + execute(Eq("CREATE TABLE IF NOT EXISTS fileStatuses(sourceId INTEGER PRIMARY KEY, " + "size INTEGER, lastModified INTEGER, isInPrecompiledHeader INTEGER)"))) + .Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS sourceDependencies(sourceId INTEGER, dependencySourceId INTEGER)"))).Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_sourceDependencies_sourceId_dependencySourceId ON sourceDependencies(sourceId, dependencySourceId)"))).Times(0); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS precompiledHeaders(projectPartId INTEGER PRIMARY KEY, pchPath TEXT, pchBuildTime INTEGER)"))).Times(0); diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index eecd388f024..1e73f8a71b2 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -73,13 +73,6 @@ using ClangBackEnd::SourceLocationKind; using ClangBackEnd::UsedMacros; using OptionalProjectPartArtefact = Utils::optional; -MATCHER_P(IsFileId, fileNameId, - std::string(negation ? "isn't " : "is ") - + PrintToString(ClangBackEnd::FilePathId(fileNameId))) -{ - return arg == ClangBackEnd::FilePathId(fileNameId); -} - struct Data { Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; @@ -211,7 +204,7 @@ protected: SourceLocationEntries sourceLocations{{1, 1, {42, 23}, SourceLocationKind::Declaration}}; FilePathIds sourceFileIds{1, 23}; UsedMacros usedMacros{{"Foo", 1}}; - FileStatuses fileStatus{{2, 3, 4, false}}; + FileStatuses fileStatus{{2, 3, 4}}; SourceDependencies sourceDependencies{{1, 2}, {1, 3}}; Utils::SmallString systemIncludeSearchPathsText{ R"([["/includes", 1, 2], [")" TESTDATA_DIR R"(" ,2 , 3], ["/other/includes", 3, 3]])"}; @@ -442,26 +435,6 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartsInStorage) indexer.updateProjectParts({projectPart1, projectPart2}); } -TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartSourcesWithArtifact) -{ - ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq("project1"))).WillByDefault(Return(artefact)); - ON_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project1"), _, _, _, _, _, _, _)).WillByDefault(Return(-1)); - - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(_, _)); - - indexer.updateProjectParts({projectPart1}); -} - -TEST_F(SymbolIndexer, UpdateProjectPartsCallsUpdateProjectPartSourcesWithoutArtifact) -{ - ON_CALL(mockSymbolStorage, fetchProjectPartArtefact(TypedEq("project2"))).WillByDefault(Return(nullArtefact)); - ON_CALL(mockSymbolStorage, insertOrUpdateProjectPart(Eq("project2"), _, _, _, _, _, _, _)).WillByDefault(Return(3)); - - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(3, ElementsAre(IsFileId(1), IsFileId(23)))); - - indexer.updateProjectParts({projectPart2}); -} - TEST_F(SymbolIndexer, UpdateProjectPartsCallsInsertOrUpdateUsedMacros) { EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))) @@ -472,7 +445,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInsertOrUpdateUsedMacros) TEST_F(SymbolIndexer, UpdateProjectPartsCallsInsertFileStatuses) { - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))) + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))) .Times(2); indexer.updateProjectParts({projectPart1, projectPart2}); @@ -538,9 +511,8 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact) EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(TypedEq(12), Eq(sourceFileIds))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); @@ -591,9 +563,8 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact) EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(TypedEq(artefact.projectPartId), Eq(sourceFileIds))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); @@ -646,9 +617,8 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderButGetsAnErrorForCollectingS EXPECT_CALL(mockCollector, collectSymbols()).WillOnce(Return(false)); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)).Times(0); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(TypedEq(12), Eq(sourceFileIds))).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))).Times(0); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))).Times(0); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))) .Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); @@ -711,9 +681,8 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder) EXPECT_CALL(mockCollector, collectSymbols()); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(artefact.projectPartId, Eq(sourceFileIds))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))); EXPECT_CALL(mockSqliteTransactionBackend, commit()); @@ -732,9 +701,8 @@ TEST_F(SymbolIndexer, HandleEmptyOptionalArtifactInUpdateChangedPath) EXPECT_CALL(mockCollector, collectSymbols()).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(_, _)).Times(0); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(An(), _)).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(_)).Times(0); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(_)).Times(0); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(_)).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(_)).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); @@ -775,10 +743,8 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrderButGetsAnErrorForCollectingSy EXPECT_CALL(mockCollector, collectSymbols()).WillOnce(Return(false)); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(symbolEntries, sourceLocations)).Times(0); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(artefact.projectPartId, Eq(sourceFileIds))) - .Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(Eq(usedMacros))).Times(0); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(Eq(fileStatus))).Times(0); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(Eq(fileStatus))).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(Eq(sourceDependencies))) .Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); @@ -950,9 +916,8 @@ TEST_F(SymbolIndexer, DontReparseInUpdateProjectPartsIfDefinesAreTheSame) EXPECT_CALL(mockCollector, collectSymbols()).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, immediateBegin()).Times(0); EXPECT_CALL(mockSymbolStorage, addSymbolsAndSourceLocations(_, _)).Times(0); - EXPECT_CALL(mockSymbolStorage, updateProjectPartSources(An(), _)).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateUsedMacros(_)).Times(0); - EXPECT_CALL(mockBuildDependenciesStorage, insertFileStatuses(_)).Times(0); + EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateFileStatuses(_)).Times(0); EXPECT_CALL(mockBuildDependenciesStorage, insertOrUpdateSourceDependencies(_)).Times(0); EXPECT_CALL(mockSqliteTransactionBackend, commit()).Times(0); diff --git a/tests/unit/unittest/symbolscollector-test.cpp b/tests/unit/unittest/symbolscollector-test.cpp index 2d7025373f3..48e4420dc12 100644 --- a/tests/unit/unittest/symbolscollector-test.cpp +++ b/tests/unit/unittest/symbolscollector-test.cpp @@ -147,7 +147,7 @@ protected: ClangBackEnd::FileStatus fileStatus(Utils::SmallStringView filePath) const { - return {filePathId(filePath), fileSize(filePath), lastModified(filePath), false}; + return {filePathId(filePath), fileSize(filePath), lastModified(filePath)}; } SymbolIndex symbolId(const Utils::SmallString &symbolName) diff --git a/tests/unit/unittest/symbolstorage-test.cpp b/tests/unit/unittest/symbolstorage-test.cpp index f9a3d0a7dee..ddd71362523 100644 --- a/tests/unit/unittest/symbolstorage-test.cpp +++ b/tests/unit/unittest/symbolstorage-test.cpp @@ -70,8 +70,6 @@ protected: MockSqliteWriteStatement &deleteNewLocationsTableStatement = storage.m_deleteNewLocationsTableStatement; MockSqliteWriteStatement &insertOrUpdateProjectPartStatement = storage.m_insertOrUpdateProjectPartStatement; MockSqliteReadStatement &getProjectPartIdStatement = storage.m_getProjectPartIdStatement; - MockSqliteWriteStatement &deleteAllProjectPartsSourcesWithProjectPartIdStatement = storage.m_deleteAllProjectPartsSourcesWithProjectPartIdStatement; - MockSqliteWriteStatement &insertProjectPartSourcesStatement = storage.m_insertProjectPartSourcesStatement; MockSqliteReadStatement &getProjectPartArtefactsBySourceId = storage.m_getProjectPartArtefactsBySourceId; MockSqliteReadStatement &getProjectPartArtefactsByProjectPartName = storage.m_getProjectPartArtefactsByProjectPartName; @@ -212,18 +210,6 @@ TEST_F(SymbolStorage, InsertOrUpdateProjectPart) Utils::LanguageExtension::None); } - -TEST_F(SymbolStorage, UpdateProjectPartSources) -{ - InSequence sequence; - - EXPECT_CALL(deleteAllProjectPartsSourcesWithProjectPartIdStatement, write(TypedEq(42))); - EXPECT_CALL(insertProjectPartSourcesStatement, write(TypedEq(42), TypedEq(1))); - EXPECT_CALL(insertProjectPartSourcesStatement, write(TypedEq(42), TypedEq(2))); - - storage.updateProjectPartSources(42, {1, 2}); -} - TEST_F(SymbolStorage, FetchProjectPartArtefactBySourceIdCallsValueInStatement) { EXPECT_CALL(getProjectPartArtefactsBySourceId, valueReturnProjectPartArtefact(1)) diff --git a/tests/unit/unittest/usedmacrocollector-test.cpp b/tests/unit/unittest/usedmacrocollector-test.cpp index 61f7fcd99b4..31aa4fab382 100644 --- a/tests/unit/unittest/usedmacrocollector-test.cpp +++ b/tests/unit/unittest/usedmacrocollector-test.cpp @@ -68,7 +68,7 @@ protected: ClangBackEnd::FileStatus fileStatus(Utils::SmallStringView filePath) const { - return {filePathId(filePath), fileSize(filePath), lastModified(filePath), false}; + return {filePathId(filePath), fileSize(filePath), lastModified(filePath)}; } protected: Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; diff --git a/tests/unit/unittest/usedmacrofilter-test.cpp b/tests/unit/unittest/usedmacrofilter-test.cpp index bdde5417afb..bfbbd7adb70 100644 --- a/tests/unit/unittest/usedmacrofilter-test.cpp +++ b/tests/unit/unittest/usedmacrofilter-test.cpp @@ -41,11 +41,12 @@ using ClangBackEnd::CompilerMacros; class UsedMacroFilter : public testing::Test { protected: - SourceEntries includes{{1, SourceType::UserInclude, 0}, - {2, SourceType::SystemInclude, 0}, - {3, SourceType::ProjectInclude, 0}, - {4, SourceType::TopSystemInclude, 0}, - {5, SourceType::TopProjectInclude, 0}}; + SourceEntries sources{{1, SourceType::UserInclude, 0}, + {2, SourceType::SystemInclude, 0}, + {3, SourceType::ProjectInclude, 0}, + {4, SourceType::TopSystemInclude, 0}, + {5, SourceType::TopProjectInclude, 0}, + {6, SourceType::Source, 0}}; UsedMacros usedMacros{{"YI", 1}, {"ER", 2}, {"SE", 2}, @@ -65,57 +66,62 @@ protected: TEST_F(UsedMacroFilter, SystemIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.systemIncludes, ElementsAre(FilePathId{2}, FilePathId{4})); } TEST_F(UsedMacroFilter, ProjectIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.projectIncludes, ElementsAre(FilePathId{3}, FilePathId{5})); } TEST_F(UsedMacroFilter, TopSystemIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.topSystemIncludes, ElementsAre(FilePathId{4})); } TEST_F(UsedMacroFilter, TopProjectIncludes) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.topProjectIncludes, ElementsAre(FilePathId{5})); } -TEST_F(UsedMacroFilter, AllIncludes) +TEST_F(UsedMacroFilter, Sources) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); - ASSERT_THAT(filter.allIncludes, - ElementsAre(FilePathId{1}, FilePathId{2}, FilePathId{3}, FilePathId{4}, FilePathId{5})); + ASSERT_THAT(filter.sources, + ElementsAre(FilePathId{1}, + FilePathId{2}, + FilePathId{3}, + FilePathId{4}, + FilePathId{5}, + FilePathId{6})); } TEST_F(UsedMacroFilter, SystemUsedMacros) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.systemUsedMacros, ElementsAre("ER", "SE", "LIU")); } TEST_F(UsedMacroFilter, ProjectUsedMacros) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.projectUsedMacros, ElementsAre("QI", "WU", "SAN")); } TEST_F(UsedMacroFilter, SystemCompileMacros) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.systemCompilerMacros, ElementsAre(CompilerMacro{"ER", "2", 2}, @@ -125,7 +131,7 @@ TEST_F(UsedMacroFilter, SystemCompileMacros) TEST_F(UsedMacroFilter, ProjectCompileMacros) { - ClangBackEnd::UsedMacroFilter filter(includes, usedMacros, compileMacros); + ClangBackEnd::UsedMacroFilter filter(sources, usedMacros, compileMacros); ASSERT_THAT(filter.projectCompilerMacros, ElementsAre(CompilerMacro{"QI"}, From 3e1faec230b226df9c1e7acfdc322c1e0c6fb426 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 28 Feb 2019 17:52:34 +0100 Subject: [PATCH 25/80] Clang: Don't filter source with missing includes We do now tag and save them. So we can reliably track them. Task-number: QTCREATORBUG-22035 Change-Id: I49aaeeb76150b7e2d77b863eeb0aedefc9ab50f4 Reviewed-by: Ivan Donchevskii --- .../refactoringdatabaseinitializer.h | 1 + .../source/builddependenciesstorage.h | 25 +++---- ...lectbuilddependencypreprocessorcallbacks.h | 46 ++++++------- .../source/sourceentry.h | 35 ++++++---- .../source/usedmacrofilter.h | 65 ++++++++++--------- .../builddependenciesstorage-test.cpp | 12 ++-- .../builddependencycollector-test.cpp | 64 ++++++++++++++++-- .../unit/unittest/gtest-creator-printing.cpp | 19 +++++- .../unit/unittest/mocksqlitereadstatement.cpp | 7 +- tests/unit/unittest/mocksqlitereadstatement.h | 7 +- .../unit/unittest/mocksqlitewritestatement.h | 2 +- .../refactoringdatabaseinitializer-test.cpp | 6 +- tests/unit/unittest/usedmacrofilter-test.cpp | 3 +- 13 files changed, 187 insertions(+), 105 deletions(-) diff --git a/src/libs/clangsupport/refactoringdatabaseinitializer.h b/src/libs/clangsupport/refactoringdatabaseinitializer.h index 6bbb650af7f..f6d64a81d31 100644 --- a/src/libs/clangsupport/refactoringdatabaseinitializer.h +++ b/src/libs/clangsupport/refactoringdatabaseinitializer.h @@ -144,6 +144,7 @@ public: const Sqlite::Column &sourceIdColumn = table.addColumn("sourceId", Sqlite::ColumnType::Integer); table.addColumn("sourceType", Sqlite::ColumnType::Integer); table.addColumn("pchCreationTimeStamp", Sqlite::ColumnType::Integer); + table.addColumn("hasMissingIncludes", Sqlite::ColumnType::Integer); table.addUniqueIndex({sourceIdColumn, projectPartIdColumn}); table.addIndex({projectPartIdColumn}); diff --git a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h index c164e7a727f..3e6d00da3f6 100644 --- a/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h +++ b/src/tools/clangpchmanagerbackend/source/builddependenciesstorage.h @@ -59,9 +59,11 @@ public: projectPartId); for (const SourceEntry &entry : sourceEntries) { - insertOrUpdateSourceTypeStatement.write(entry.sourceId.filePathId, - projectPartId, - static_cast(entry.sourceType)); + insertOrUpdateProjectPartsSourcesStatement.write( + entry.sourceId.filePathId, + projectPartId, + static_cast(entry.sourceType), + static_cast(entry.hasMissingIncludes)); } } @@ -120,9 +122,8 @@ public: SourceEntries fetchDependSources(FilePathId sourceId, int projectPartId) const override { - return fetchSourceDependenciesStatement.template values(300, - sourceId.filePathId, - projectPartId); + return fetchSourceDependenciesStatement.template values( + 300, sourceId.filePathId, projectPartId); } UsedMacros fetchUsedMacros(FilePathId sourceId) const override @@ -242,20 +243,20 @@ public: "DELETE FROM newSourceDependencies", database }; - WriteStatement insertOrUpdateSourceTypeStatement{ + WriteStatement insertOrUpdateProjectPartsSourcesStatement{ "INSERT INTO projectPartsSources(sourceId, projectPartId, " - "sourceType) VALUES (?001, ?002, ?003) ON CONFLICT(sourceId, " - "projectPartId) DO UPDATE SET sourceType = ?003", + "sourceType, hasMissingIncludes) VALUES (?001, ?002, ?003, ?004) ON " + "CONFLICT(sourceId, projectPartId) DO UPDATE SET sourceType = ?003, " + "hasMissingIncludes = ?004", database}; mutable ReadStatement fetchSourceDependenciesStatement{ "WITH RECURSIVE collectedDependencies(sourceId) AS (VALUES(?) UNION " "SELECT dependencySourceId FROM sourceDependencies, " "collectedDependencies WHERE sourceDependencies.sourceId == " "collectedDependencies.sourceId) SELECT sourceId, " - "pchCreationTimeStamp, sourceType FROM " + "pchCreationTimeStamp, sourceType, hasMissingIncludes FROM " "collectedDependencies NATURAL JOIN projectPartsSources WHERE " - "projectPartId = ? ORDER BY " - "sourceId", + "projectPartId = ? ORDER BY sourceId", database}; mutable ReadStatement fetchProjectPartIdStatement{ "SELECT projectPartId FROM projectParts WHERE projectPartName = ?", diff --git a/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h index 658c51cb1a3..f3b365d8d54 100644 --- a/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectbuilddependencypreprocessorcallbacks.h @@ -204,10 +204,10 @@ public: void appendContainsMissingIncludes(const FilePathIds &dependentSourceFilesWithMissingIncludes) { - auto split = m_containsMissingIncludes - .insert(m_containsMissingIncludes.end(), - dependentSourceFilesWithMissingIncludes.begin(), - dependentSourceFilesWithMissingIncludes.end()); + auto split = m_containsMissingIncludes.insert( + m_containsMissingIncludes.end(), + dependentSourceFilesWithMissingIncludes.begin(), + dependentSourceFilesWithMissingIncludes.end()); std::inplace_merge(m_containsMissingIncludes.begin(), split, m_containsMissingIncludes.end()); @@ -217,11 +217,13 @@ public: { FilePathIds filteredDependentSourceFilesWithMissingIncludes; filteredDependentSourceFilesWithMissingIncludes.reserve(dependentSourceFilesWithMissingIncludes.size()); - std::set_difference(dependentSourceFilesWithMissingIncludes.begin(), - dependentSourceFilesWithMissingIncludes.end(), - m_containsMissingIncludes.begin(), - m_containsMissingIncludes.end(), - std::back_inserter(filteredDependentSourceFilesWithMissingIncludes)); + std::set_difference( + dependentSourceFilesWithMissingIncludes.begin(), + dependentSourceFilesWithMissingIncludes.end(), + m_containsMissingIncludes.begin(), + m_containsMissingIncludes.end(), + std::back_inserter( + filteredDependentSourceFilesWithMissingIncludes)); dependentSourceFilesWithMissingIncludes = filteredDependentSourceFilesWithMissingIncludes; } @@ -265,8 +267,7 @@ public: sourceDependencies); } - void removeSourceWithMissingIncludesFromIncludes() - { + void removeSourceWithMissingIncludesFromSources() { class Compare { public: @@ -280,17 +281,16 @@ public: } }; - auto &includes = m_buildDependency.sources; - SourceEntries newIncludes; - newIncludes.reserve(includes.size()); - std::set_difference(includes.begin(), - includes.end(), - m_containsMissingIncludes.begin(), - m_containsMissingIncludes.end(), - std::back_inserter(newIncludes), - Compare{}); - - m_buildDependency.sources = newIncludes; + SourceEntryReferences sourcesWithMissingIncludes; + sourcesWithMissingIncludes.reserve(m_containsMissingIncludes.size()); + std::set_intersection(m_buildDependency.sources.begin(), + m_buildDependency.sources.end(), + m_containsMissingIncludes.begin(), + m_containsMissingIncludes.end(), + std::back_inserter(sourcesWithMissingIncludes), + Compare{}); + for (SourceEntryReference entry : sourcesWithMissingIncludes) + entry.get().hasMissingIncludes = HasMissingIncludes::Yes; } SourceDependencies sourceDependenciesSortedByDependendFilePathId() const @@ -311,7 +311,7 @@ public: collectSourceWithMissingIncludes(m_containsMissingIncludes, sourceDependenciesSortedByDependendFilePathId()); - removeSourceWithMissingIncludesFromIncludes(); + removeSourceWithMissingIncludesFromSources(); } void ensureDirectory(const QString &directory, const QString &fileName) diff --git a/src/tools/clangpchmanagerbackend/source/sourceentry.h b/src/tools/clangpchmanagerbackend/source/sourceentry.h index d5bb28d904f..5c45db6bde9 100644 --- a/src/tools/clangpchmanagerbackend/source/sourceentry.h +++ b/src/tools/clangpchmanagerbackend/source/sourceentry.h @@ -40,6 +40,8 @@ enum class SourceType : unsigned char { Source }; +enum class HasMissingIncludes : unsigned char { No, Yes }; + class TimeStamp { using int64 = long long; @@ -108,20 +110,23 @@ class SourceEntry using int64 = long long; public: - SourceEntry(int sourceId, int64 pchCreationTimeStamp, int sourceType) - : pchCreationTimeStamp(pchCreationTimeStamp) - , sourceId(sourceId) - , sourceType(static_cast(sourceType)) - {} + SourceEntry(int sourceId, + int64 pchCreationTimeStamp, + int sourceType, + int hasMissingIncludes) + : pchCreationTimeStamp(pchCreationTimeStamp), sourceId(sourceId), + sourceType(static_cast(sourceType)), + hasMissingIncludes( + static_cast(hasMissingIncludes)) {} - SourceEntry(FilePathId sourceId, SourceType sourceType, TimeStamp pchCreationTimeStamp) - : pchCreationTimeStamp(pchCreationTimeStamp) - , sourceId(sourceId) - , sourceType(sourceType) - {} + SourceEntry(FilePathId sourceId, + SourceType sourceType, + TimeStamp pchCreationTimeStamp, + HasMissingIncludes hasMissingIncludes = HasMissingIncludes::No) + : pchCreationTimeStamp(pchCreationTimeStamp), sourceId(sourceId), + sourceType(sourceType), hasMissingIncludes(hasMissingIncludes) {} - friend bool operator<(SourceEntry first, SourceEntry second) - { + friend bool operator<(SourceEntry first, SourceEntry second) { return first.sourceId < second.sourceId; } @@ -137,8 +142,10 @@ public: TimeStamp pchCreationTimeStamp; FilePathId sourceId; SourceType sourceType = SourceType::UserInclude; + HasMissingIncludes hasMissingIncludes = HasMissingIncludes::No; }; using SourceEntries = std::vector; - -} +using SourceEntryReference = std::reference_wrapper; +using SourceEntryReferences = std::vector; +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h index bd9788e61cb..9db3c683b90 100644 --- a/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h +++ b/src/tools/clangpchmanagerbackend/source/usedmacrofilter.h @@ -87,23 +87,22 @@ public: UsedMacroFilter(const SourceEntries &includes, const UsedMacros &usedMacros, - const CompilerMacros &compilerMacros) - { - filterIncludes(includes); + const CompilerMacros &compilerMacros) { + filterSources(includes); systemUsedMacros = filterUsedMarcos(usedMacros, systemIncludes); projectUsedMacros = filterUsedMarcos(usedMacros, projectIncludes); filter(compilerMacros); } - void filterIncludes(const SourceEntries &includes) - { - systemIncludes.reserve(includes.size()); - projectIncludes.reserve(includes.size()); - topSystemIncludes.reserve(includes.size() / 10); - topProjectIncludes.reserve(includes.size() / 10); + void filterSources(const SourceEntries &sources) { + systemIncludes.reserve(sources.size()); + projectIncludes.reserve(sources.size()); + topSystemIncludes.reserve(sources.size() / 10); + topProjectIncludes.reserve(sources.size() / 10); + this->sources.reserve(sources.size()); - for (SourceEntry include : includes) - filterInclude(include); + for (SourceEntry source : sources) + filterSource(source); } void filter(const CompilerMacros &compilerMacros) @@ -121,29 +120,31 @@ public: } private: - void filterInclude(SourceEntry include) - { - switch (include.sourceType) { - case SourceType::TopSystemInclude: - topSystemIncludes.emplace_back(include.sourceId); - systemIncludes.emplace_back(include.sourceId); - break; - case SourceType::SystemInclude: - systemIncludes.emplace_back(include.sourceId); - break; - case SourceType::TopProjectInclude: - topProjectIncludes.emplace_back(include.sourceId); - projectIncludes.emplace_back(include.sourceId); - break; - case SourceType::ProjectInclude: - projectIncludes.emplace_back(include.sourceId); - break; - case SourceType::UserInclude: - case SourceType::Source: - break; + void filterSource(SourceEntry source) { + if (source.hasMissingIncludes == HasMissingIncludes::Yes) + return; + + switch (source.sourceType) { + case SourceType::TopSystemInclude: + topSystemIncludes.emplace_back(source.sourceId); + systemIncludes.emplace_back(source.sourceId); + break; + case SourceType::SystemInclude: + systemIncludes.emplace_back(source.sourceId); + break; + case SourceType::TopProjectInclude: + topProjectIncludes.emplace_back(source.sourceId); + projectIncludes.emplace_back(source.sourceId); + break; + case SourceType::ProjectInclude: + projectIncludes.emplace_back(source.sourceId); + break; + case SourceType::UserInclude: + case SourceType::Source: + break; } - sources.emplace_back(include.sourceId); + sources.emplace_back(source.sourceId); } static Utils::SmallStringVector filterUsedMarcos(const UsedMacros &usedMacros, diff --git a/tests/unit/unittest/builddependenciesstorage-test.cpp b/tests/unit/unittest/builddependenciesstorage-test.cpp index 8112107e2b5..30db7ea408a 100644 --- a/tests/unit/unittest/builddependenciesstorage-test.cpp +++ b/tests/unit/unittest/builddependenciesstorage-test.cpp @@ -61,7 +61,7 @@ protected: MockSqliteWriteStatement &deleteOutdatedSourceDependenciesStatement = storage.deleteOutdatedSourceDependenciesStatement; MockSqliteWriteStatement &deleteNewSourceDependenciesStatement = storage.deleteNewSourceDependenciesStatement; MockSqliteReadStatement &getLowestLastModifiedTimeOfDependencies = storage.getLowestLastModifiedTimeOfDependencies; - MockSqliteWriteStatement &insertOrUpdateSourceTypeStatement = storage.insertOrUpdateSourceTypeStatement; + MockSqliteWriteStatement &insertOrUpdateProjectPartsSourcesStatement = storage.insertOrUpdateProjectPartsSourcesStatement; MockSqliteReadStatement &fetchSourceDependenciesStatement = storage.fetchSourceDependenciesStatement; MockSqliteReadStatement &fetchProjectPartIdStatement = storage.fetchProjectPartIdStatement; MockSqliteReadStatement &fetchUsedMacrosStatement = storage.fetchUsedMacrosStatement; @@ -174,14 +174,14 @@ TEST_F(BuildDependenciesStorage, AddNewSourceDependenciesTable) TEST_F(BuildDependenciesStorage, UpdateSources) { InSequence s; - SourceEntries entries{{1, SourceType::TopProjectInclude, 10}, + SourceEntries entries{{1, SourceType::TopProjectInclude, 10, ClangBackEnd::HasMissingIncludes::Yes}, {2, SourceType::TopSystemInclude, 20}}; EXPECT_CALL(deleteAllProjectPartsSourcesWithProjectPartNameStatement, write(TypedEq(22))); - EXPECT_CALL(insertOrUpdateSourceTypeStatement, - write(TypedEq(1), TypedEq(22), TypedEq(0))); - EXPECT_CALL(insertOrUpdateSourceTypeStatement, - write(TypedEq(2), TypedEq(22), TypedEq(1))); + EXPECT_CALL(insertOrUpdateProjectPartsSourcesStatement, + write(TypedEq(1), TypedEq(22), TypedEq(0), TypedEq(1))); + EXPECT_CALL(insertOrUpdateProjectPartsSourcesStatement, + write(TypedEq(2), TypedEq(22), TypedEq(1), TypedEq(0))); storage.insertOrUpdateSources(entries, 22); } diff --git a/tests/unit/unittest/builddependencycollector-test.cpp b/tests/unit/unittest/builddependencycollector-test.cpp index d8965c0a9f8..58506662322 100644 --- a/tests/unit/unittest/builddependencycollector-test.cpp +++ b/tests/unit/unittest/builddependencycollector-test.cpp @@ -47,6 +47,7 @@ using ClangBackEnd::BuildDependency; using ClangBackEnd::FilePathId; using ClangBackEnd::FilePathIds; using ClangBackEnd::FilePathView; +using ClangBackEnd::HasMissingIncludes; using ClangBackEnd::SourceDependency; using ClangBackEnd::SourceType; using ClangBackEnd::UsedMacro; @@ -57,11 +58,26 @@ MATCHER_P2(HasSource, sourceId, sourceType, std::string(negation ? "hasn't " : "has ") - + PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType, -1))) + + PrintToString(ClangBackEnd::SourceEntry( + sourceId, sourceType, -1, ClangBackEnd::HasMissingIncludes::No))) { const ClangBackEnd::SourceEntry &entry = arg; - return entry.sourceId == sourceId && entry.sourceType == sourceType; + return entry.sourceId == sourceId && entry.sourceType == sourceType + && entry.hasMissingIncludes == ClangBackEnd::HasMissingIncludes::No; +} + +MATCHER_P3(HasSource, + sourceId, + sourceType, + hasMissingIncludes, + std::string(negation ? "hasn't " : "has ") + + PrintToString(ClangBackEnd::SourceEntry(sourceId, sourceType, -1, hasMissingIncludes))) +{ + const ClangBackEnd::SourceEntry &entry = arg; + + return entry.sourceId == sourceId && entry.sourceType == sourceType + && entry.hasMissingIncludes == hasMissingIncludes; } class BuildDependencyCollector : public ::testing::Test @@ -199,6 +215,7 @@ TEST_F(BuildDependencyCollector, NoDuplicate) ASSERT_THAT(sources(collector.sourceEntries()), UnorderedElementsAre( id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), + id(TESTDATA_DIR "/builddependencycollector/project/main2.cpp"), id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), @@ -214,6 +231,7 @@ TEST_F(BuildDependencyCollector, IncludesAreSorted) ASSERT_THAT(sources(collector.sourceEntries()), ElementsAre(id(TESTDATA_DIR "/builddependencycollector/project/main.cpp"), + id(TESTDATA_DIR "/builddependencycollector/project/main2.cpp"), id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), id(TESTDATA_DIR "/builddependencycollector/external/external3.h"), @@ -262,6 +280,7 @@ TEST_F(BuildDependencyCollector, IgnoreMissingFile) ASSERT_THAT(sources(emptyCollector.sourceEntries()), UnorderedElementsAre( + id(TESTDATA_DIR "/builddependencycollector/project/missingfile.cpp"), id(TESTDATA_DIR "/builddependencycollector/external/external1.h"), id(TESTDATA_DIR "/builddependencycollector/external/indirect_external.h"), id(TESTDATA_DIR "/builddependencycollector/external/indirect_external2.h"))); @@ -634,10 +653,37 @@ TEST_F(BuildDependencyCollector, MissingInclude) emptyCollector.collect(); - ASSERT_THAT(emptyCollector.sourceEntries(), - ElementsAre( - HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), - SourceType::UserInclude))); + ASSERT_THAT( + emptyCollector.sourceEntries(), + UnorderedElementsAre( + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/main5.cpp"), + SourceType::Source, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/missinginclude2.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/project/indirect_missinginclude.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/project/indirect_missinginclude3.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/project/indirect_missinginclude4.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/missinginclude3.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR + "/builddependencycollector/project/indirect_missinginclude2.h"), + SourceType::ProjectInclude, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), + SourceType::UserInclude, + HasMissingIncludes::No))); } @@ -735,6 +781,12 @@ TEST_F(BuildDependencyCollector, Create) Field( &BuildDependency::sources, UnorderedElementsAre( + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/main4.cpp"), + SourceType::Source, + HasMissingIncludes::Yes), + HasSource(id(TESTDATA_DIR "/builddependencycollector/project/missingfile.h"), + SourceType::UserInclude, + HasMissingIncludes::Yes), HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header1.h"), SourceType::UserInclude), HasSource(id(TESTDATA_DIR "/builddependencycollector/project/header2.h"), diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp index 63dde52dc21..2befb52417c 100644 --- a/tests/unit/unittest/gtest-creator-printing.cpp +++ b/tests/unit/unittest/gtest-creator-printing.cpp @@ -1179,7 +1179,7 @@ std::ostream &operator<<(std::ostream &out, const SlotUsage &slotUsage) return out << "(" << slotUsage.free << ", " << slotUsage.used << ")"; } -const char *sourceTypeString(SourceType sourceType) +const char *typeToString(SourceType sourceType) { using ClangBackEnd::SymbolTag; @@ -1201,9 +1201,24 @@ const char *sourceTypeString(SourceType sourceType) return ""; } +const char *typeToString(HasMissingIncludes hasMissingIncludes) +{ + using ClangBackEnd::SymbolTag; + + switch (hasMissingIncludes) { + case HasMissingIncludes::No: + return "HasMissingIncludes::No"; + case HasMissingIncludes::Yes: + return "HasMissingIncludes::Yes"; + } + + return ""; +} + std::ostream &operator<<(std::ostream &out, const SourceEntry &entry) { - return out << "(" << entry.sourceId << ", " << sourceTypeString(entry.sourceType) << ")"; + return out << "(" << entry.sourceId << ", " << typeToString(entry.sourceType) << ", " + << typeToString(entry.hasMissingIncludes) << ")"; } const char *typeToString(IncludeSearchPathType type) diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp index b9cecd4d1aa..04d2a07c142 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.cpp +++ b/tests/unit/unittest/mocksqlitereadstatement.cpp @@ -186,9 +186,10 @@ MockSqliteReadStatement::value(const long long &symbolId, con return valueReturnSourceLocation(symbolId, locationKind); } -template <> -SourceEntries -MockSqliteReadStatement::values(std::size_t reserveSize, const int &filePathId, const int &projectPartId) +template<> +SourceEntries MockSqliteReadStatement::values(std::size_t reserveSize, + const int &filePathId, + const int &projectPartId) { return valuesReturnSourceEntries(reserveSize, filePathId, projectPartId); } diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h index 43c88eb0441..5c6fbdef772 100644 --- a/tests/unit/unittest/mocksqlitereadstatement.h +++ b/tests/unit/unittest/mocksqlitereadstatement.h @@ -255,9 +255,10 @@ template <> Utils::optional MockSqliteReadStatement::value(const long long &symbolId, const int &locationKind); -template <> -SourceEntries -MockSqliteReadStatement::values(std::size_t reserveSize, const int&, const int&); +template<> +SourceEntries MockSqliteReadStatement::values(std::size_t reserveSize, + const int &, + const int &); template <> Utils::optional diff --git a/tests/unit/unittest/mocksqlitewritestatement.h b/tests/unit/unittest/mocksqlitewritestatement.h index edaea7d7e18..4b369845aa6 100644 --- a/tests/unit/unittest/mocksqlitewritestatement.h +++ b/tests/unit/unittest/mocksqlitewritestatement.h @@ -109,7 +109,7 @@ public: MOCK_METHOD2(write, void (uchar, int)); - MOCK_METHOD3(write, void(int, int, uchar)); + MOCK_METHOD4(write, void(int, int, uchar, uchar)); MOCK_METHOD2(write, void (long long, int)); MOCK_METHOD2(write, void(long long, Utils::SmallStringView)); diff --git a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp index 34eaec10bdd..ebd67dccba0 100644 --- a/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp +++ b/tests/unit/unittest/refactoringdatabaseinitializer-test.cpp @@ -104,7 +104,8 @@ TEST_F(RefactoringDatabaseInitializer, AddProjectPartsSourcesTable) EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " - "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER)"))); + "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER, " + "hasMissingIncludes INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON projectPartsSources(projectPartId)"))); @@ -179,7 +180,8 @@ TEST_F(RefactoringDatabaseInitializer, CreateInTheContructor) EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectParts_projectPartName ON projectParts(projectPartName)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS projectPartsSources(projectPartId INTEGER, " - "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER)"))); + "sourceId INTEGER, sourceType INTEGER, pchCreationTimeStamp INTEGER, " + "hasMissingIncludes INTEGER)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE UNIQUE INDEX IF NOT EXISTS index_projectPartsSources_sourceId_projectPartId ON projectPartsSources(sourceId, projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE INDEX IF NOT EXISTS index_projectPartsSources_projectPartId ON projectPartsSources(projectPartId)"))); EXPECT_CALL(mockDatabase, execute(Eq("CREATE TABLE IF NOT EXISTS usedMacros(usedMacroId INTEGER PRIMARY KEY, sourceId INTEGER, macroName TEXT)"))); diff --git a/tests/unit/unittest/usedmacrofilter-test.cpp b/tests/unit/unittest/usedmacrofilter-test.cpp index bfbbd7adb70..788a443eee2 100644 --- a/tests/unit/unittest/usedmacrofilter-test.cpp +++ b/tests/unit/unittest/usedmacrofilter-test.cpp @@ -46,7 +46,8 @@ protected: {3, SourceType::ProjectInclude, 0}, {4, SourceType::TopSystemInclude, 0}, {5, SourceType::TopProjectInclude, 0}, - {6, SourceType::Source, 0}}; + {6, SourceType::Source, 0}, + {7, SourceType::TopProjectInclude, 0, ClangBackEnd::HasMissingIncludes::Yes}}; UsedMacros usedMacros{{"YI", 1}, {"ER", 2}, {"SE", 2}, From e7fd132d4712a9204a9eb7e70eded0aabae71778 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 28 Feb 2019 19:22:22 +0100 Subject: [PATCH 26/80] Clang: Disable warnings in CommandLineBuilder Change-Id: I7597d57a0bb97facefb08c9c1bbe6e909c146080 Reviewed-by: Ivan Donchevskii --- src/libs/clangsupport/commandlinebuilder.h | 3 +++ tests/unit/unittest/commandlinebuilder-test.cpp | 15 +++++++++++++++ tests/unit/unittest/pchcreator-test.cpp | 2 ++ tests/unit/unittest/symbolindexer-test.cpp | 10 ++++++++++ 4 files changed, 30 insertions(+) diff --git a/src/libs/clangsupport/commandlinebuilder.h b/src/libs/clangsupport/commandlinebuilder.h index 7367f080360..9de1da68d3c 100644 --- a/src/libs/clangsupport/commandlinebuilder.h +++ b/src/libs/clangsupport/commandlinebuilder.h @@ -51,6 +51,7 @@ public: commandLine.reserve(1024); addCompiler(projectInfo.language); + disableWarnings(); addToolChainArguments(toolChainArguments); addExtraFlags(); addLanguage(projectInfo, sourceType); @@ -74,6 +75,8 @@ public: commandLine.emplace_back("clang"); } + void disableWarnings() { commandLine.emplace_back("-w"); } + void addToolChainArguments(const Utils::SmallStringVector &toolChainArguments) { for (Utils::SmallStringView argument : toolChainArguments) diff --git a/tests/unit/unittest/commandlinebuilder-test.cpp b/tests/unit/unittest/commandlinebuilder-test.cpp index a75c8d8a35c..328b832b9c4 100644 --- a/tests/unit/unittest/commandlinebuilder-test.cpp +++ b/tests/unit/unittest/commandlinebuilder-test.cpp @@ -139,6 +139,7 @@ TYPED_TEST(CommandLineBuilder, CHeader) ASSERT_THAT(builder.commandLine, ElementsAre("clang", + "-w", "-DNOMINMAX", "-x", "c-header", @@ -156,6 +157,7 @@ TYPED_TEST(CommandLineBuilder, CSource) ASSERT_THAT(builder.commandLine, ElementsAre("clang", + "-w", "-DNOMINMAX", "-x", "c", @@ -174,6 +176,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCHeader) ASSERT_THAT(builder.commandLine, ElementsAre("clang", + "-w", "-DNOMINMAX", "-x", "objective-c-header", @@ -192,6 +195,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCSource) ASSERT_THAT(builder.commandLine, ElementsAre("clang", + "-w", "-DNOMINMAX", "-x", "objective-c", @@ -209,6 +213,7 @@ TYPED_TEST(CommandLineBuilder, CppHeader) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -227,6 +232,7 @@ TYPED_TEST(CommandLineBuilder, CppSource) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++", @@ -246,6 +252,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppHeader) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "objective-c++-header", @@ -265,6 +272,7 @@ TYPED_TEST(CommandLineBuilder, ObjectiveCppSource) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "objective-c++", @@ -498,6 +506,7 @@ TYPED_TEST(CommandLineBuilder, IncludesOrder) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -525,6 +534,7 @@ TYPED_TEST(CommandLineBuilder, EmptySourceFile) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -539,6 +549,7 @@ TYPED_TEST(CommandLineBuilder, SourceFile) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -555,6 +566,7 @@ TYPED_TEST(CommandLineBuilder, EmptyOutputFile) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -574,6 +586,7 @@ TYPED_TEST(CommandLineBuilder, OutputFile) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -596,6 +609,7 @@ TYPED_TEST(CommandLineBuilder, IncludePchPath) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -619,6 +633,7 @@ TYPED_TEST(CommandLineBuilder, CompilerMacros) ASSERT_THAT(builder.commandLine, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index b28769b51bb..3dbafc8aa08 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -141,6 +141,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArguments) ASSERT_THAT(arguments, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", @@ -165,6 +166,7 @@ TEST_F(PchCreator, CreateProjectPartClangCompilerArgumentsWithSystemPch) ASSERT_THAT(arguments, ElementsAre("clang++", + "-w", "-DNOMINMAX", "-x", "c++-header", diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp index 1e73f8a71b2..ea015bdee65 100644 --- a/tests/unit/unittest/symbolindexer-test.cpp +++ b/tests/unit/unittest/symbolindexer-test.cpp @@ -262,6 +262,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesInCollector) EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -294,6 +295,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithPrecompiledHeaderInColl EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -328,6 +330,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsAddFilesWithoutPrecompiledHeaderInC EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -489,6 +492,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithoutProjectPartArtifact) EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -541,6 +545,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderWithProjectPartArtifact) EXPECT_CALL(mockCollector, setFile(Eq(main1PathId), ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -595,6 +600,7 @@ TEST_F(SymbolIndexer, UpdateProjectPartsCallsInOrderButGetsAnErrorForCollectingS EXPECT_CALL(mockCollector, setFile(main1PathId, ElementsAre("clang++", + "-w", "-Wno-pragma-once-outside-header", "-DNOMINMAX", "-x", @@ -659,6 +665,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrder) EXPECT_CALL(mockCollector, setFile(Eq(sourceFileIds[0]), ElementsAre("clang++", + "-w", "-DFOO", "-DNOMINMAX", "-x", @@ -721,6 +728,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathCallsInOrderButGetsAnErrorForCollectingSy EXPECT_CALL(mockCollector, setFile(Eq(sourceFileIds[0]), ElementsAre("clang++", + "-w", "-DFOO", "-DNOMINMAX", "-x", @@ -763,6 +771,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsUsingPrecompiledHeader) EXPECT_CALL(mockCollector, setFile(Eq(sourceFileIds[0]), ElementsAre("clang++", + "-w", "-DFOO", "-DNOMINMAX", "-x", @@ -799,6 +808,7 @@ TEST_F(SymbolIndexer, UpdateChangedPathIsNotUsingPrecompiledHeaderIfItNotExists) EXPECT_CALL(mockCollector, setFile(Eq(sourceFileIds[0]), ElementsAre("clang++", + "-w", "-DFOO", "-DNOMINMAX", "-x", From 70d4e46552fe64106aa15f578f180a0afc623050 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 4 Mar 2019 14:42:16 +0100 Subject: [PATCH 27/80] Clang: Rename ProjectParts in ProjectPartsManager Change-Id: Ia60d78e34a296b0b379339ebc14efd0e81dc8989 Reviewed-by: Ivan Donchevskii --- .../clangpchmanagerbackendmain.cpp | 6 ++-- .../source/clangpchmanagerbackend-source.pri | 8 ++--- .../source/pchmanagerserver.cpp | 22 ++++++------ .../source/pchmanagerserver.h | 6 ++-- ...ojectparts.cpp => projectpartsmanager.cpp} | 18 +++++----- .../{projectparts.h => projectpartsmanager.h} | 5 ++- ...rface.h => projectpartsmanagerinterface.h} | 10 +++--- tests/unit/unittest/mockprojectparts.h | 4 +-- tests/unit/unittest/pchmanagerserver-test.cpp | 35 +++++++++++-------- tests/unit/unittest/projectparts-test.cpp | 4 +-- 10 files changed, 61 insertions(+), 57 deletions(-) rename src/tools/clangpchmanagerbackend/source/{projectparts.cpp => projectpartsmanager.cpp} (86%) rename src/tools/clangpchmanagerbackend/source/{projectparts.h => projectpartsmanager.h} (94%) rename src/tools/clangpchmanagerbackend/source/{projectpartsinterface.h => projectpartsmanagerinterface.h} (85%) diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 0bc807a03d2..3237aab2fb1 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -68,7 +68,7 @@ using ClangBackEnd::PchCreator; using ClangBackEnd::PchManagerClientProxy; using ClangBackEnd::PchManagerServer; using ClangBackEnd::PrecompiledHeaderStorage; -using ClangBackEnd::ProjectParts; +using ClangBackEnd::ProjectPartsManager; using ClangBackEnd::FilePathCache; using ClangBackEnd::FilePathView; using ClangBackEnd::TimeStamp; @@ -179,7 +179,7 @@ struct Data // because we have a cycle dependency ClangBackEnd::FilePathCaching filePathCache{database}; ClangPathWatcher includeWatcher{filePathCache}; ApplicationEnvironment environment; - ProjectParts projectParts; + ProjectPartsManager projectParts; GeneratedFiles generatedFiles; PchCreatorManager pchCreatorManager{generatedFiles, environment, diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri index fa8d6e527a6..61bcedc262d 100644 --- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri +++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri @@ -3,19 +3,19 @@ INCLUDEPATH += $$PWD SOURCES += \ $$PWD/builddependenciesprovider.cpp \ $$PWD/pchmanagerserver.cpp \ - $$PWD/projectparts.cpp \ $$PWD/pchtaskgenerator.cpp \ $$PWD/pchtasksmerger.cpp \ - $$PWD/pchtaskqueue.cpp + $$PWD/pchtaskqueue.cpp \ + $$PWD/projectpartsmanager.cpp HEADERS += \ $$PWD/pchmanagerserver.h \ $$PWD/clangpchmanagerbackend_global.h \ $$PWD/pchnotcreatederror.h \ $$PWD/environment.h \ - $$PWD/projectparts.h \ $$PWD/pchcreatorinterface.h \ - $$PWD/projectpartsinterface.h \ + $$PWD/projectpartsmanager.h \ + $$PWD/projectpartsmanagerinterface.h \ $$PWD/queueinterface.h \ $$PWD/processormanagerinterface.h \ $$PWD/processorinterface.h \ diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp index 999da264488..89ad9126402 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp @@ -42,12 +42,12 @@ namespace ClangBackEnd { PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, PchTaskGeneratorInterface &pchTaskGenerator, - ProjectPartsInterface &projectParts, + ProjectPartsManagerInterface &projectParts, GeneratedFilesInterface &generatedFiles) - : m_fileSystemWatcher(fileSystemWatcher), - m_pchTaskGenerator(pchTaskGenerator), - m_projectParts(projectParts), - m_generatedFiles(generatedFiles) + : m_fileSystemWatcher(fileSystemWatcher) + , m_pchTaskGenerator(pchTaskGenerator) + , m_projectPartsManager(projectParts) + , m_generatedFiles(generatedFiles) { m_fileSystemWatcher.setNotifier(this); } @@ -61,13 +61,13 @@ void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message) { m_toolChainsArgumentsCache.update(message.projectsParts, message.toolChainArguments); - ProjectPartContainers newProjectParts = m_projectParts.update(message.takeProjectsParts()); + ProjectPartContainers newProjectParts = m_projectPartsManager.update(message.takeProjectsParts()); if (m_generatedFiles.isValid()) { m_pchTaskGenerator.addProjectParts(std::move(newProjectParts), std::move(message.toolChainArguments)); } else { - m_projectParts.updateDeferred(newProjectParts); + m_projectPartsManager.updateDeferred(newProjectParts); } } @@ -75,7 +75,7 @@ void PchManagerServer::removeProjectParts(RemoveProjectPartsMessage &&message) { m_fileSystemWatcher.removeIds(message.projectsPartIds); - m_projectParts.remove(message.projectsPartIds); + m_projectPartsManager.remove(message.projectsPartIds); m_pchTaskGenerator.removeProjectParts(message.projectsPartIds); @@ -102,7 +102,7 @@ void PchManagerServer::updateGeneratedFiles(UpdateGeneratedFilesMessage &&messag m_generatedFiles.update(message.takeGeneratedFiles()); if (m_generatedFiles.isValid()) { - ProjectPartContainers deferredProjectParts = m_projectParts.deferredUpdates(); + ProjectPartContainers deferredProjectParts = m_projectPartsManager.deferredUpdates(); ArgumentsEntries entries = m_toolChainsArgumentsCache.arguments( projectPartIds(deferredProjectParts)); @@ -123,8 +123,8 @@ void PchManagerServer::pathsWithIdsChanged(const Utils::SmallStringVector &ids) ArgumentsEntries entries = m_toolChainsArgumentsCache.arguments(ids); for (ArgumentsEntry &entry : entries) { - m_pchTaskGenerator.addProjectParts( - m_projectParts.projects(entry.ids), std::move(entry.arguments)); + m_pchTaskGenerator.addProjectParts(m_projectPartsManager.projects(entry.ids), + std::move(entry.arguments)); } } diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h index bf6b5bd7e76..9cf8aa83217 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h @@ -29,7 +29,7 @@ #include "clangpathwatchernotifier.h" #include "pchcreatorinterface.h" #include "pchmanagerserverinterface.h" -#include "projectpartsinterface.h" +#include "projectpartsmanagerinterface.h" #include "toolchainargumentscache.h" #include @@ -48,7 +48,7 @@ class PchManagerServer : public PchManagerServerInterface, public: PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, PchTaskGeneratorInterface &pchTaskGenerator, - ProjectPartsInterface &projectParts, + ProjectPartsManagerInterface &projectParts, GeneratedFilesInterface &generatedFiles); void end() override; @@ -66,7 +66,7 @@ public: private: ClangPathWatcherInterface &m_fileSystemWatcher; PchTaskGeneratorInterface &m_pchTaskGenerator; - ProjectPartsInterface &m_projectParts; + ProjectPartsManagerInterface &m_projectPartsManager; GeneratedFilesInterface &m_generatedFiles; ToolChainsArgumentsCache m_toolChainsArgumentsCache; }; diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.cpp b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp similarity index 86% rename from src/tools/clangpchmanagerbackend/source/projectparts.cpp rename to src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp index e8df25e1042..8333ed96740 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.cpp +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp @@ -23,7 +23,7 @@ ** ****************************************************************************/ -#include "projectparts.h" +#include "projectpartsmanager.h" #include @@ -33,7 +33,7 @@ namespace ClangBackEnd { inline namespace Pch { -ProjectPartContainers ProjectParts::update(ProjectPartContainers &&projectsParts) +ProjectPartContainers ProjectPartsManager::update(ProjectPartContainers &&projectsParts) { auto updatedProjectPartContainers = newProjectParts(std::move(projectsParts)); @@ -42,7 +42,7 @@ ProjectPartContainers ProjectParts::update(ProjectPartContainers &&projectsParts return updatedProjectPartContainers; } -void ProjectParts::remove(const Utils::SmallStringVector &ids) +void ProjectPartsManager::remove(const Utils::SmallStringVector &ids) { auto shouldRemove = [&] (const ProjectPartContainer &projectPart) { return std::find(ids.begin(), ids.end(), projectPart.projectPartId) != ids.end(); @@ -52,7 +52,7 @@ void ProjectParts::remove(const Utils::SmallStringVector &ids) m_projectParts.erase(newEnd, m_projectParts.end()); } -ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector &projectPartIds) const +ProjectPartContainers ProjectPartsManager::projects(const Utils::SmallStringVector &projectPartIds) const { ProjectPartContainers projectPartsWithIds; @@ -66,7 +66,7 @@ ProjectPartContainers ProjectParts::projects(const Utils::SmallStringVector &pro return projectPartsWithIds; } -void ProjectParts::updateDeferred(const ProjectPartContainers &deferredProjectsParts) +void ProjectPartsManager::updateDeferred(const ProjectPartContainers &deferredProjectsParts) { using ProjectPartContainerReferences = std::vector>; @@ -86,7 +86,7 @@ void ProjectParts::updateDeferred(const ProjectPartContainers &deferredProjectsP projectPart.updateIsDeferred = true; } -ProjectPartContainers ProjectParts::deferredUpdates() +ProjectPartContainers ProjectPartsManager::deferredUpdates() { ProjectPartContainers deferredProjectParts; deferredProjectParts.reserve(m_projectParts.size()); @@ -102,7 +102,7 @@ ProjectPartContainers ProjectParts::deferredUpdates() return deferredProjectParts; } -ProjectPartContainers ProjectParts::newProjectParts(ProjectPartContainers &&projectsParts) const +ProjectPartContainers ProjectPartsManager::newProjectParts(ProjectPartContainers &&projectsParts) const { ProjectPartContainers updatedProjectPartContainers; updatedProjectPartContainers.reserve(projectsParts.size()); @@ -116,7 +116,7 @@ ProjectPartContainers ProjectParts::newProjectParts(ProjectPartContainers &&proj return updatedProjectPartContainers; } -void ProjectParts::mergeProjectParts(const ProjectPartContainers &projectsParts) +void ProjectPartsManager::mergeProjectParts(const ProjectPartContainers &projectsParts) { ProjectPartContainers newProjectParts; newProjectParts.reserve(m_projectParts.size() + projectsParts.size()); @@ -135,7 +135,7 @@ void ProjectParts::mergeProjectParts(const ProjectPartContainers &projectsParts) m_projectParts = newProjectParts; } -const ProjectPartContainers &ProjectParts::projectParts() const +const ProjectPartContainers &ProjectPartsManager::projectParts() const { return m_projectParts; } diff --git a/src/tools/clangpchmanagerbackend/source/projectparts.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h similarity index 94% rename from src/tools/clangpchmanagerbackend/source/projectparts.h rename to src/tools/clangpchmanagerbackend/source/projectpartsmanager.h index 4df413ce6f0..2b3c43ebc8b 100644 --- a/src/tools/clangpchmanagerbackend/source/projectparts.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h @@ -27,15 +27,14 @@ #include "clangpchmanagerbackend_global.h" -#include +#include #include namespace ClangBackEnd { inline namespace Pch { - -class ProjectParts final : public ProjectPartsInterface +class ProjectPartsManager final : public ProjectPartsManagerInterface { public: ProjectPartContainers update(ProjectPartContainers &&projectsParts) override; diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h similarity index 85% rename from src/tools/clangpchmanagerbackend/source/projectpartsinterface.h rename to src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h index d37673af100..f99674ddda2 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsinterface.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h @@ -29,12 +29,12 @@ namespace ClangBackEnd { -class ProjectPartsInterface +class ProjectPartsManagerInterface { public: - ProjectPartsInterface() = default; - ProjectPartsInterface(const ProjectPartsInterface &) = delete; - ProjectPartsInterface &operator=(const ProjectPartsInterface &) = delete; + ProjectPartsManagerInterface() = default; + ProjectPartsManagerInterface(const ProjectPartsManagerInterface &) = delete; + ProjectPartsManagerInterface &operator=(const ProjectPartsManagerInterface &) = delete; virtual ProjectPartContainers update(ProjectPartContainers &&projectsParts) = 0; virtual void remove(const Utils::SmallStringVector &projectPartIds) = 0; @@ -42,7 +42,7 @@ public: virtual void updateDeferred(const ProjectPartContainers &projectsParts) = 0; virtual ProjectPartContainers deferredUpdates() = 0; protected: - ~ProjectPartsInterface() = default; + ~ProjectPartsManagerInterface() = default; }; } // namespace ClangBackEnd diff --git a/tests/unit/unittest/mockprojectparts.h b/tests/unit/unittest/mockprojectparts.h index 7c7a2daf4aa..15ec0238468 100644 --- a/tests/unit/unittest/mockprojectparts.h +++ b/tests/unit/unittest/mockprojectparts.h @@ -27,9 +27,9 @@ #include "googletest.h" -#include +#include -class MockProjectParts : public ClangBackEnd::ProjectPartsInterface +class MockProjectPartsManager : public ClangBackEnd::ProjectPartsManagerInterface { public: MOCK_METHOD1(update, diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp index 5a2ca172c00..370667edc84 100644 --- a/tests/unit/unittest/pchmanagerserver-test.cpp +++ b/tests/unit/unittest/pchmanagerserver-test.cpp @@ -55,7 +55,7 @@ class PchManagerServer : public ::testing::Test { server.setClient(&mockPchManagerClient); - ON_CALL(mockProjectParts, update(projectParts)).WillByDefault(Return(projectParts)); + ON_CALL(mockProjectPartsManager, update(projectParts)).WillByDefault(Return(projectParts)); ON_CALL(mockGeneratedFiles, isValid()).WillByDefault(Return(true)); } @@ -67,13 +67,15 @@ class PchManagerServer : public ::testing::Test protected: NiceMock mockPchTaskGenerator; NiceMock mockClangPathWatcher; - NiceMock mockProjectParts; + NiceMock mockProjectPartsManager; NiceMock mockGeneratedFiles; Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; ClangBackEnd::RefactoringDatabaseInitializer initializer{database}; ClangBackEnd::FilePathCaching filePathCache{database}; - ClangBackEnd::PchManagerServer server{ - mockClangPathWatcher, mockPchTaskGenerator, mockProjectParts, mockGeneratedFiles}; + ClangBackEnd::PchManagerServer server{mockClangPathWatcher, + mockPchTaskGenerator, + mockProjectPartsManager, + mockGeneratedFiles}; NiceMock mockPchManagerClient; SmallString projectPartId1 = "project1"; SmallString projectPartId2 = "project2"; @@ -117,7 +119,7 @@ TEST_F(PchManagerServer, FilterProjectPartsAndSendThemToQueue) { InSequence s; - EXPECT_CALL(mockProjectParts, update(updateProjectPartsMessage.projectsParts)) + EXPECT_CALL(mockProjectPartsManager, update(updateProjectPartsMessage.projectsParts)) .WillOnce(Return(projectParts2)); EXPECT_CALL( mockPchTaskGenerator, addProjectParts(Eq(projectParts2), ElementsAre("toolChainArgument"))); @@ -152,7 +154,7 @@ TEST_F(PchManagerServer, RemoveIncludesFromFileWatcher) TEST_F(PchManagerServer, RemoveProjectPartsFromProjectParts) { - EXPECT_CALL(mockProjectParts, remove(removeProjectPartsMessage.projectsPartIds)); + EXPECT_CALL(mockProjectPartsManager, remove(removeProjectPartsMessage.projectsPartIds)); server.removeProjectParts(removeProjectPartsMessage.clone()); } @@ -161,7 +163,10 @@ TEST_F(PchManagerServer, SetPathWatcherNotifier) { EXPECT_CALL(mockClangPathWatcher, setNotifier(_)); - ClangBackEnd::PchManagerServer server{mockClangPathWatcher, mockPchTaskGenerator, mockProjectParts, mockGeneratedFiles}; + ClangBackEnd::PchManagerServer server{mockClangPathWatcher, + mockPchTaskGenerator, + mockProjectPartsManager, + mockGeneratedFiles}; } TEST_F(PchManagerServer, UpdateProjectPartQueueByPathIds) @@ -169,8 +174,8 @@ TEST_F(PchManagerServer, UpdateProjectPartQueueByPathIds) server.updateProjectParts( ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); - EXPECT_CALL(mockProjectParts, projects(ElementsAre(projectPart1.projectPartId))) - .WillOnce(Return(std::vector{{projectPart1}})); + EXPECT_CALL(mockProjectPartsManager, projects(ElementsAre(projectPart1.projectPartId))) + .WillOnce(Return(std::vector{{projectPart1}})); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(ElementsAre(projectPart1), ElementsAre("toolChainArgument"))); server.pathsWithIdsChanged({projectPartId1}); @@ -213,11 +218,11 @@ TEST_F(PchManagerServer, DontGeneratePchIfGeneratedFilesAreNotValid) { InSequence s; - EXPECT_CALL(mockProjectParts, update(ElementsAre(projectPart1))) + EXPECT_CALL(mockProjectPartsManager, update(ElementsAre(projectPart1))) .WillOnce(Return(ProjectPartContainers{projectPart1})); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false)); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); - EXPECT_CALL(mockProjectParts, updateDeferred(ElementsAre(projectPart1))); + EXPECT_CALL(mockProjectPartsManager, updateDeferred(ElementsAre(projectPart1))); server.updateProjectParts( ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); @@ -227,11 +232,11 @@ TEST_F(PchManagerServer, GeneratePchIfGeneratedFilesAreValid) { InSequence s; - EXPECT_CALL(mockProjectParts, update(ElementsAre(projectPart1))) + EXPECT_CALL(mockProjectPartsManager, update(ElementsAre(projectPart1))) .WillOnce(Return(ProjectPartContainers{projectPart1})); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true)); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)); - EXPECT_CALL(mockProjectParts, updateDeferred(_)).Times(0); + EXPECT_CALL(mockProjectPartsManager, updateDeferred(_)).Times(0); server.updateProjectParts( ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); @@ -247,7 +252,7 @@ TEST_F(PchManagerServer, AfterUpdatingGeneratedFilesAreValidSoGeneratePchs) EXPECT_CALL(mockGeneratedFiles, update(updateGeneratedFilesMessage.generatedFiles)); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true)); - EXPECT_CALL(mockProjectParts, deferredUpdates()) + EXPECT_CALL(mockProjectPartsManager, deferredUpdates()) .WillOnce(Return(ClangBackEnd::ProjectPartContainers{projectPart1})); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(ElementsAre(projectPart1), ElementsAre("toolChainArgument"))); @@ -265,7 +270,7 @@ TEST_F(PchManagerServer, AfterUpdatingGeneratedFilesAreStillInvalidSoNoPchsGener EXPECT_CALL(mockGeneratedFiles, update(updateGeneratedFilesMessage.generatedFiles)); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false)); - EXPECT_CALL(mockProjectParts, deferredUpdates()).Times(0); + EXPECT_CALL(mockProjectPartsManager, deferredUpdates()).Times(0); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); server.updateGeneratedFiles(updateGeneratedFilesMessage.clone()); diff --git a/tests/unit/unittest/projectparts-test.cpp b/tests/unit/unittest/projectparts-test.cpp index 8ab342b2f18..16f1ef09889 100644 --- a/tests/unit/unittest/projectparts-test.cpp +++ b/tests/unit/unittest/projectparts-test.cpp @@ -25,7 +25,7 @@ #include "googletest.h" -#include +#include #include @@ -41,7 +41,7 @@ using ClangBackEnd::FilePathId; class ProjectParts : public testing::Test { protected: - ClangBackEnd::ProjectParts projectParts; + ClangBackEnd::ProjectPartsManager projectParts; FilePathId firstHeader{1}; FilePathId secondHeader{2}; FilePathId firstSource{11}; From 6146ff4495e30df88794841e512092efb00351be Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 5 Mar 2019 17:53:18 +0100 Subject: [PATCH 28/80] ClangTools: Remove misused plural Change-Id: I1d88f2b94621988b671ce18a4bfb7d9741994e82 Reviewed-by: Ivan Donchevskii Reviewed-by: Leena Miettinen --- src/plugins/clangtools/clangtidyclazytool.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/clangtools/clangtidyclazytool.cpp b/src/plugins/clangtools/clangtidyclazytool.cpp index 3453975a9c5..6d10e8d5f57 100644 --- a/src/plugins/clangtools/clangtidyclazytool.cpp +++ b/src/plugins/clangtools/clangtidyclazytool.cpp @@ -452,12 +452,12 @@ void ClangTidyClazyTool::handleStateUpdate() if (issuesFound) message = tr("Running - %n diagnostics", nullptr, issuesFound); else - message = tr("Running - No diagnostics", nullptr, issuesFound); + message = tr("Running - No diagnostics"); } else { if (issuesFound) message = tr("Finished - %n diagnostics", nullptr, issuesFound); else - message = tr("Finished - No diagnostics", nullptr, issuesFound); + message = tr("Finished - No diagnostics"); } Debugger::showPermanentStatusMessage(message); From 70661a57f05937ee4cc6bd3d0de36097598e9f38 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 6 Mar 2019 10:57:42 +0100 Subject: [PATCH 29/80] ClangFormat: Change plugin from "experimental" to "disabled by default" Change-Id: I81a2c21c6d4aea6febd4ac68cc79045b803eba05 Reviewed-by: Eike Ziller Reviewed-by: Marco Bubke --- src/plugins/clangformat/ClangFormat.json.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/clangformat/ClangFormat.json.in b/src/plugins/clangformat/ClangFormat.json.in index 1c818c2f9e4..f270fea580e 100644 --- a/src/plugins/clangformat/ClangFormat.json.in +++ b/src/plugins/clangformat/ClangFormat.json.in @@ -2,7 +2,7 @@ \"Name\" : \"ClangFormat\", \"Version\" : \"$$QTCREATOR_VERSION\", \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", - \"Experimental\" : true, + \"DisabledByDefault\" : true, \"Vendor\" : \"The Qt Company Ltd\", \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", \"License\" : [ \"Commercial Usage\", From 6b5b5692e4693f929fbbd78fa4f1b889f4857899 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 6 Mar 2019 13:04:34 +0100 Subject: [PATCH 30/80] ClangFormat: Fix UTF-16 line and column for 0 offset Change-Id: I348a32d623da1c2da7f3e7f18cad8c9c06dc7b06 Reviewed-by: Marco Bubke --- src/libs/utils/textutils.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/textutils.cpp b/src/libs/utils/textutils.cpp index 0d8009fef89..ba10ca56ae4 100644 --- a/src/libs/utils/textutils.cpp +++ b/src/libs/utils/textutils.cpp @@ -171,7 +171,8 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) lineColumn.line = static_cast( std::count(utf8Buffer.begin(), utf8Buffer.begin() + utf8Offset, '\n')) + 1; - const int startOfLineOffset = utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1; + const int startOfLineOffset = utf8Offset ? (utf8Buffer.lastIndexOf('\n', utf8Offset - 1) + 1) + : 0; lineColumn.column = QString::fromUtf8( utf8Buffer.mid(startOfLineOffset, utf8Offset - startOfLineOffset)) .length() @@ -181,7 +182,9 @@ LineColumn utf16LineColumn(const QByteArray &utf8Buffer, int utf8Offset) QString utf16LineTextInUtf8Buffer(const QByteArray &utf8Buffer, int currentUtf8Offset) { - const int lineStartUtf8Offset = utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1; + const int lineStartUtf8Offset = currentUtf8Offset + ? (utf8Buffer.lastIndexOf('\n', currentUtf8Offset - 1) + 1) + : 0; const int lineEndUtf8Offset = utf8Buffer.indexOf('\n', currentUtf8Offset); return QString::fromUtf8( utf8Buffer.mid(lineStartUtf8Offset, lineEndUtf8Offset - lineStartUtf8Offset)); From 7236e340a968be964e67ced3f29eadf76787fdcf Mon Sep 17 00:00:00 2001 From: illiteratecoder Date: Tue, 5 Mar 2019 16:07:16 -0800 Subject: [PATCH 31/80] Debugger: Fix std::{unordered_,}{map,set} dumper for libc++ Task-number: QTCREATORBUG-18536 Change-Id: I2842a525e99e4fcd9544a1f15bd42fd5c8c0c16e (cherry picked from commit 7b39db9e8a0e36ad59eae0a7dea776d4205032a8) Reviewed-by: Christian Stenger --- share/qtcreator/debugger/stdtypes.py | 128 +++++++++++++++++---------- 1 file changed, 81 insertions(+), 47 deletions(-) diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index 8810e099127..cca73b7717a 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -507,23 +507,30 @@ def std1TreeNext(d, node): return node['__parent_'] def qdump__std____1__set(d, value): - tree = value["__tree_"] - base3 = tree["__pair3_"].address() - size = d.extractUInt(base3) - d.check(size <= 100*1000*1000) + (proxy, head, size) = value.split("ppp") + + d.check(0 <= size and size <= 100*1000*1000) d.putItemCount(size) + if d.isExpanded(): - # type of node is std::__1::__tree_node::value_type valueType = value.type[0] - d.putFields(tree) - node = tree["__begin_node_"] - nodeType = node.type - with Children(d, size): - for i in d.childRange(): - with SubItem(d, i): - d.putItem(node['__value_']) - d.putBetterType(valueType) - node = std1TreeNext(d, node).cast(nodeType) + + def in_order_traversal(node): + (left, right, parent, color, pad, data) = d.split("pppB@{%s}" % (valueType.name), node) + + if left: + for res in in_order_traversal(left): + yield res + + yield data + + if right: + for res in in_order_traversal(right): + yield res + + with Children(d, size, maxNumChild=1000): + for (i, data) in zip(d.childRange(), in_order_traversal(head)): + d.putSubItem(i, data) def qdump__std____1__multiset(d, value): qdump__std____1__set(d, value) @@ -532,24 +539,38 @@ def qform__std____1__map(): return mapForms() def qdump__std____1__map(d, value): - tree = value["__tree_"] - base3 = tree["__pair3_"].address() - size = d.extractUInt(base3) - d.check(size <= 100*1000*1000) + try: + (proxy, head, size) = value.split("ppp") + d.check(0 <= size and size <= 100*1000*1000) + + # Sometimes there is extra data at the front. Don't know why at the moment. + except RuntimeError: + (junk, proxy, head, size) = value.split("pppp") + d.check(0 <= size and size <= 100*1000*1000) + d.putItemCount(size) + if d.isExpanded(): - # type of node is std::__1::__tree_node::value_type - valueType = value.type[0] - node = tree["__begin_node_"] - nodeType = node.type + keyType = value.type[0] + valueType = value.type[1] + pairType = value.type[3][0] + + def in_order_traversal(node): + (left, right, parent, color, pad, pair) = d.split("pppB@{%s}" % (pairType.name), node) + + if left: + for res in in_order_traversal(left): + yield res + + yield pair.split("{%s}@{%s}" % (keyType.name, valueType.name))[::2] + + if right: + for res in in_order_traversal(right): + yield res + with Children(d, size, maxNumChild=1000): - node = tree["__begin_node_"] - for i in d.childRange(): - # There's possibly also: - #pair = node['__value_']['__nc'] - pair = node['__value_']['__cc'] - d.putPairItem(i, pair) - node = std1TreeNext(d, node).cast(nodeType) + for (i, pair) in zip(d.childRange(), in_order_traversal(head)): + d.putPairItem(i, pair, 'key', 'value') def qform__std____1__multimap(): return mapForms() @@ -833,32 +854,45 @@ def qform__std____1__unordered_map(): return mapForms() def qdump__std____1__unordered_map(d, value): - size = value["__table_"]["__p2_"]["__first_"].integer() + (size, _) = value["__table_"]["__p2_"].split("pp") d.putItemCount(size) - if d.isExpanded(): - # There seem to be several versions of the implementation. - def valueCCorNot(val): - try: - return val["__cc"] - except: - return val - node = value["__table_"]["__p1_"]["__first_"]["__next_"] - with Children(d, size): - for i in d.childRange(): - d.putPairItem(i, valueCCorNot(node["__value_"])) - node = node["__next_"] + keyType = value.type[0] + valueType = value.type[1] + pairType = value.type[4][0] + + if d.isExpanded(): + curr = value["__table_"]["__p1_"].split("pp")[0] + + def traverse_list(node): + while node: + (next_, _, pad, pair) = d.split("pp@{%s}" % (pairType.name), node) + yield pair.split("{%s}@{%s}" % (keyType.name, valueType.name))[::2] + node = next_ + + with Children(d, size, childType=value.type[0], maxNumChild=1000): + for (i, value) in zip(d.childRange(), traverse_list(curr)): + d.putPairItem(i, value, 'key', 'value') def qdump__std____1__unordered_set(d, value): - size = int(value["__table_"]["__p2_"]["__first_"]) + (size, _) = value["__table_"]["__p2_"].split("pp") d.putItemCount(size) + + valueType = value.type[0] + if d.isExpanded(): - node = value["__table_"]["__p1_"]["__first_"]["__next_"] + curr = value["__table_"]["__p1_"].split("pp")[0] + + def traverse_list(node): + while node: + (next_, _, pad, val) = d.split("pp@{%s}" % (valueType.name), node) + yield val + node = next_ + with Children(d, size, childType=value.type[0], maxNumChild=1000): - for i in d.childRange(): - d.putSubItem(i, node["__value_"]) - node = node["__next_"] + for (i, value) in zip(d.childRange(), traverse_list(curr)): + d.putSubItem(i, value) def qdump__std____debug__unordered_set(d, value): From 35b0b44b21cd24e76455525c25b0b9ab08349233 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 6 Mar 2019 12:47:45 +0100 Subject: [PATCH 32/80] ClangFormat: Enable includes sorting Sort includes only in modes when all replacements are used (manual indentation with "Format instead of indent" selected and saving with "Format on save" activated). Change-Id: I73dfa1d3211760269fe7d33a141f4d831ff65c15 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 20 +++++++++++++++++-- tests/unit/unittest/clangformat-test.cpp | 17 ++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 09ae5a6bccb..c8ab31813c7 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -33,6 +33,7 @@ #include #include +#include namespace ClangFormat { @@ -420,9 +421,24 @@ TextEditor::Replacements ClangFormatBaseIndenter::format( static_cast(utf8RangeLength)); } + clang::format::FormatStyle style = styleForFile(); + const std::string assumedFileName = m_fileName.toString().toStdString(); + clang::tooling::Replacements clangReplacements = clang::format::sortIncludes(style, + buffer.data(), + ranges, + assumedFileName); + auto changedCode = clang::tooling::applyAllReplacements(buffer.data(), clangReplacements); + QTC_ASSERT(changedCode, { + qDebug() << QString::fromStdString(llvm::toString(changedCode.takeError())); + return TextEditor::Replacements(); + }); + ranges = clang::tooling::calculateRangesAfterReplacements(clangReplacements, ranges); + clang::format::FormattingAttemptStatus status; - const clang::tooling::Replacements clangReplacements - = reformat(styleForFile(), buffer.data(), ranges, m_fileName.toString().toStdString(), &status); + const clang::tooling::Replacements formatReplacements + = reformat(style, *changedCode, ranges, m_fileName.toString().toStdString(), &status); + clangReplacements = clangReplacements.merge(formatReplacements); + const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements); applyReplacements(m_doc, toReplace); diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 5f0aaf1d873..5dbe291b26b 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -633,6 +633,23 @@ TEST_F(ClangFormat, FormatTemplateparameters) ASSERT_THAT(documentLines(), ElementsAre("using Alias = Template")); } + +TEST_F(ClangFormat, SortIncludes) +{ + insertLines({"#include \"b.h\"", + "#include \"a.h\"", + "", + "#include ", + "#include "}); + + indenter.format({{1, 5}}); + + ASSERT_THAT(documentLines(), ElementsAre("#include \"a.h\"", + "#include \"b.h\"", + "", + "#include ", + "#include ")); +} // clang-format on } // namespace From 7e5e99d551e1c393e3eebb4e952202c6418cd2fa Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 6 Mar 2019 14:05:31 +0100 Subject: [PATCH 33/80] ClangFormat: Add whitespace unit-tests and fix bugs Check that extra whitespace does not prevent the indentation and that indentation is the same for the consecutive empty lines. Change-Id: I04aa12c4cd31aaf07daf9320c98d2eea7afcc9a8 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 50 +++++++++++-------- .../clangformat/clangformatbaseindenter.h | 1 - tests/unit/unittest/clangformat-test.cpp | 30 +++++++++++ 3 files changed, 59 insertions(+), 22 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index c8ab31813c7..7f47b418a77 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -129,7 +129,10 @@ void trimRHSWhitespace(const QTextBlock &block) // Add extra text in case of the empty line or the line starting with ')'. // Track such extra pieces of text in isInsideModifiedLine(). -int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool secondTry) +int forceIndentWithExtraText(QByteArray &buffer, + QByteArray &dummyText, + const QTextBlock &block, + bool secondTry) { const QString blockText = block.text(); int firstNonWhitespace = Utils::indexOf(blockText, @@ -144,21 +147,26 @@ int forceIndentWithExtraText(QByteArray &buffer, const QTextBlock &block, bool s const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; - int extraLength = 0; if (firstNonWhitespace < 0 || closingParenBlock) { - //This extra text works for the most cases. - QByteArray dummyText("a;a;"); + if (dummyText.isEmpty()) { + // If we don't know yet the dummy text, let's guess it and use for this line and before. + // This extra text works for the most cases. + dummyText = "a;a;"; - // Search for previous character - QTextBlock prevBlock = block.previous(); - bool prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); - while (prevBlockIsEmpty) { - prevBlock = prevBlock.previous(); - prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); + // Search for previous character + QTextBlock prevBlock = block.previous(); + bool prevBlockIsEmpty = prevBlock.position() > 0 + && prevBlock.text().trimmed().isEmpty(); + while (prevBlockIsEmpty) { + prevBlock = prevBlock.previous(); + prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); + } + if (prevBlock.text().endsWith(',')) + dummyText = "&& a,"; + else if (closingParenBlock) + dummyText = "&& a"; } - if (closingParenBlock || prevBlock.text().endsWith(',')) - dummyText = "&& a,"; buffer.insert(utf8Offset, dummyText); extraLength += dummyText.length(); @@ -357,8 +365,11 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer adjustFormatStyleForLineBreak(style, replacementsToKeep); if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) { - for (int index = startBlock.blockNumber(); index <= endBlock.blockNumber(); ++index) { + QByteArray dummyText; + // Iterate backwards to reuse the same dummy text for all empty lines. + for (int index = endBlock.blockNumber(); index >= startBlock.blockNumber(); --index) { utf8Length += forceIndentWithExtraText(buffer, + dummyText, m_doc->findBlockByNumber(index), secondTry); } @@ -447,7 +458,6 @@ TextEditor::Replacements ClangFormatBaseIndenter::format( TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock, const QTextBlock &endBlock, - const QByteArray &buffer, const QChar &typedChar, int cursorPositionInEditor) { @@ -465,6 +475,8 @@ TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlo cursorPositionInEditor += startBlock.position() - startBlockPosition; } + const QByteArray buffer = m_doc->toPlainText().toUtf8(); + ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent; if (formatWhileTyping() && (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition) @@ -491,9 +503,7 @@ void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock, const QChar &typedChar, int cursorPositionInEditor) { - const QByteArray buffer = m_doc->toPlainText().toUtf8(); - applyReplacements(m_doc, - indentsFor(startBlock, endBlock, buffer, typedChar, cursorPositionInEditor)); + applyReplacements(m_doc, indentsFor(startBlock, endBlock, typedChar, cursorPositionInEditor)); } void ClangFormatBaseIndenter::indent(const QTextCursor &cursor, @@ -537,15 +547,14 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block, const TextEditor::TabSettings & /*tabSettings*/, int cursorPositionInEditor) { - const QByteArray buffer = m_doc->toPlainText().toUtf8(); TextEditor::Replacements toReplace = indentsFor(block, block, - buffer, QChar::Null, cursorPositionInEditor); if (toReplace.empty()) return -1; + const QByteArray buffer = m_doc->toPlainText().toUtf8(); return indentationForBlock(toReplace, buffer, block); } @@ -557,13 +566,12 @@ TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks( TextEditor::IndentationForBlock ret; if (blocks.isEmpty()) return ret; - const QByteArray buffer = m_doc->toPlainText().toUtf8(); TextEditor::Replacements toReplace = indentsFor(blocks.front(), blocks.back(), - buffer, QChar::Null, cursorPositionInEditor); + const QByteArray buffer = m_doc->toPlainText().toUtf8(); for (const QTextBlock &block : blocks) ret.insert(block.blockNumber(), indentationForBlock(toReplace, buffer, block)); return ret; diff --git a/src/plugins/clangformat/clangformatbaseindenter.h b/src/plugins/clangformat/clangformatbaseindenter.h index b412b57d6d4..87b5e0c927b 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.h +++ b/src/plugins/clangformat/clangformatbaseindenter.h @@ -81,7 +81,6 @@ private: int cursorPositionInEditor); TextEditor::Replacements indentsFor(QTextBlock startBlock, const QTextBlock &endBlock, - const QByteArray &buffer, const QChar &typedChar, int cursorPositionInEditor); TextEditor::Replacements replacements(QByteArray buffer, diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 5dbe291b26b..43380c85028 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -72,6 +72,7 @@ protected: void insertLines(const std::vector &lines) { + doc.clear(); cursor.setPosition(0); for (size_t lineNumber = 1; lineNumber <= lines.size(); ++lineNumber) { if (lineNumber > 1) @@ -379,6 +380,17 @@ TEST_F(ClangFormat, IndentOnElectricCharacterButNotRemoveEmptyLinesBefore) "}")); } +TEST_F(ClangFormat, IndentAfterExtraSpaceInpreviousLine) +{ + insertLines({"if (a ", + "&& b)"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a", + " && b)")); +} + TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", @@ -520,6 +532,24 @@ TEST_F(ClangFormat, OnlyIndentClosingParenthesis) " )")); } +TEST_F(ClangFormat, EquallyIndentInsideParenthesis) +{ + insertLines({"if (a", + ")"}); + extendedIndenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + auto linesAfterFirstLineBreak = documentLines(); + insertLines({"if (a", + " ", + ")"}); + extendedIndenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(linesAfterFirstLineBreak, ElementsAre("if (a", + " )")); + ASSERT_THAT(documentLines(), ElementsAre("if (a", + " ", + " )")); +} + TEST_F(ClangFormat, FormatBasicFile) { insertLines({"int main()", From 0abcf7b61802b580175bfda7be78c88d70182b8f Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 6 Mar 2019 14:45:47 +0100 Subject: [PATCH 34/80] ClangFormat: Fix path for the overridden project configuration Change-Id: I4748c994016851293a6ad5490208fb4e4bbc7999 Reviewed-by: Marco Bubke --- src/plugins/clangformat/clangformatconfigwidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index feb61f3276a..72e1778999a 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -102,6 +102,7 @@ void ClangFormatConfigWidget::showGlobalCheckboxes() static bool projectConfigExists() { return Utils::FileName::fromString(Core::ICore::userResourcePath()) + .appendPath("clang-format") .appendPath(currentProjectUniqueId()) .appendPath((Constants::SETTINGS_FILE_NAME)) .exists(); @@ -208,7 +209,7 @@ void ClangFormatConfigWidget::apply() QString filePath = Core::ICore::userResourcePath(); if (m_project) - filePath += "/" + currentProjectUniqueId(); + filePath += "/clang-format/" + currentProjectUniqueId(); filePath += "/" + QLatin1String(Constants::SETTINGS_FILE_NAME); QFile file(filePath); From efecd9ac4d13e8a353971bc1970fcc907b115c86 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Tue, 5 Mar 2019 17:36:41 +0100 Subject: [PATCH 35/80] QmlDesigner: Try to shorten and clarify context menus Change-Id: I7a5258ac02869f158d881de8628726272bd05c08 Reviewed-by: Leena Miettinen Reviewed-by: Thomas Hartmann --- .../timelineeditor/timelineconstants.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h index b6c087aee4b..6c012beec1e 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineconstants.h @@ -46,13 +46,13 @@ const int priorityTimelineCategory = 110; const char timelineCategoryDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Timeline"); const char timelineCopyKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Copy All Keyframes from Item"); + "Copy All Keyframes"); const char timelinePasteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Paste Keyframes to Item"); + "Paste Keyframes"); const char timelineInsertKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Insert Keyframes for Item"); + "Add Keyframes at Current Frame"); const char timelineDeleteKeyframesDisplayName[] = QT_TRANSLATE_NOOP("QmlDesignerContextMenu", - "Delete All Keyframes for Item"); + "Delete All Keyframes"); const char timelineStatusBarFrameNumber[] = QT_TRANSLATE_NOOP("QmlDesignerTimeline", "Frame %1"); From 1f3f15f01df64bea5b1e0217ebea456e9c84d311 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 18 Feb 2019 15:49:07 +0100 Subject: [PATCH 36/80] Search results: Open editor on pressing enter on file item Only do that on enter/return, not on double-click which also expands the item (we don't want double-click to do both). Task-number: QTCREATORBUG-18200 Change-Id: Ib4f939a76054832f12b84c8e4353b88e010f1126 Reviewed-by: David Schulz --- .../coreplugin/find/searchresulttreeview.cpp | 15 +++++++++++++++ .../coreplugin/find/searchresulttreeview.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/plugins/coreplugin/find/searchresulttreeview.cpp b/src/plugins/coreplugin/find/searchresulttreeview.cpp index 6a9b7067bf4..0ca09fcefd1 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.cpp +++ b/src/plugins/coreplugin/find/searchresulttreeview.cpp @@ -78,6 +78,21 @@ void SearchResultTreeView::addResults(const QList &items, Sear } } +void SearchResultTreeView::keyPressEvent(QKeyEvent *event) +{ + if ((event->key() == Qt::Key_Return + || event->key() == Qt::Key_Enter) + && event->modifiers() == 0 + && currentIndex().isValid() + && state() != QAbstractItemView::EditingState) { + const SearchResultItem item + = model()->data(currentIndex(), ItemDataRoles::ResultItemRole).value(); + emit jumpToSearchResult(item); + return; + } + TreeView::keyPressEvent(event); +} + void SearchResultTreeView::emitJumpToSearchResult(const QModelIndex &index) { if (model()->data(index, ItemDataRoles::IsGeneratedRole).toBool()) diff --git a/src/plugins/coreplugin/find/searchresulttreeview.h b/src/plugins/coreplugin/find/searchresulttreeview.h index 961940fe017..eb11d29a7d9 100644 --- a/src/plugins/coreplugin/find/searchresulttreeview.h +++ b/src/plugins/coreplugin/find/searchresulttreeview.h @@ -49,6 +49,8 @@ public: SearchResultTreeModel *model() const; void addResults(const QList &items, SearchResult::AddMode mode); + void keyPressEvent(QKeyEvent *event) override; + signals: void jumpToSearchResult(const SearchResultItem &item); From 016eb4872f469ec25b144a9fb83b76650d56eabc Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 6 Mar 2019 17:11:59 +0100 Subject: [PATCH 37/80] QmlDesigner: Add a setting to enable the QtQuick.Timeline editor A setting with a checkbox is better than an environment variable. This patch therefore also reverts 41d19e99e04de6115887e68cb9109461774e17ba Change-Id: I35cd7134c538c64679771a44291399f6b537f2ba Reviewed-by: Leena Miettinen Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/designersettings.h | 1 - src/plugins/qmldesigner/qmldesignerplugin.cpp | 3 +-- src/plugins/qmldesigner/settingspage.cpp | 9 ++++++++- src/plugins/qmldesigner/settingspage.ui | 16 ++++++++++++++++ 4 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/designersettings.h b/src/plugins/qmldesigner/designersettings.h index 9b73dc1faf8..bdaa22bb4b2 100644 --- a/src/plugins/qmldesigner/designersettings.h +++ b/src/plugins/qmldesigner/designersettings.h @@ -65,7 +65,6 @@ const char REFORMAT_UI_QML_FILES[] = "ReformatUiQmlFiles"; /* These setti const char IGNORE_DEVICE_PIXEL_RATIO[] = "IgnoreDevicePixelRaio"; /* The settings can be used to turn off the feature, if there are serious issues */ const char STANDALONE_MODE[] = "StandAloneMode"; const char ENABLE_TIMELINEVIEW[] = "EnableTimelineView"; -const char ENABLE_TIMELINEVIEW_ENVVAR[] = "QTC_ENABLE_QTQUICKTIMELINE_EDITOR"; } class DesignerSettings : public QHash diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 09e10c3b0c1..84b95cccc3b 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -194,8 +194,7 @@ bool QmlDesignerPlugin::delayedInitialize() d->settings.fromSettings(Core::ICore::settings()); d->viewManager.registerViewTakingOwnership(new QmlDesigner::Internal::ConnectionView); - if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool() - || qEnvironmentVariableIsSet(DesignerSettingsKey::ENABLE_TIMELINEVIEW_ENVVAR)) + if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()) d->viewManager.registerViewTakingOwnership(new QmlDesigner::TimelineView); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::SourceTool); d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::ColorTool); diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index e9bd2d1cb46..a7d6bc2bb09 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -159,6 +159,8 @@ DesignerSettings SettingsPageWidget::settings() const m_ui.showPropertyEditorWarningsCheckBox->isChecked()); settings.insert(DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT, m_ui.showWarnExceptionsCheckBox->isChecked()); + settings.insert(DesignerSettingsKey::ENABLE_TIMELINEVIEW, + m_ui.featureTimelineEditorCheckBox->isChecked()); return settings; } @@ -224,9 +226,13 @@ void SettingsPageWidget::setSettings(const DesignerSettings &settings) m_ui.controls2StyleComboBox->setCurrentText(m_ui.styleLineEdit->text()); + m_ui.featureTimelineEditorCheckBox->setChecked(settings.value( + DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()); + if (settings.value(DesignerSettingsKey::STANDALONE_MODE).toBool()) { m_ui.emulationGroupBox->hide(); m_ui.debugGroupBox->hide(); + m_ui.featuresGroupBox->hide(); } } @@ -262,7 +268,8 @@ void SettingsPage::apply() << DesignerSettingsKey::PUPPET_KILL_TIMEOUT << DesignerSettingsKey::FORWARD_PUPPET_OUTPUT << DesignerSettingsKey::DEBUG_PUPPET - << DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT; + << DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT + << DesignerSettingsKey::ENABLE_TIMELINEVIEW; foreach (const QByteArray &key, restartNecessaryKeys) { if (currentSettings.value(key) != newSettings.value(key)) { diff --git a/src/plugins/qmldesigner/settingspage.ui b/src/plugins/qmldesigner/settingspage.ui index 567f0f7d80e..7da62b300aa 100644 --- a/src/plugins/qmldesigner/settingspage.ui +++ b/src/plugins/qmldesigner/settingspage.ui @@ -410,6 +410,22 @@ + + + + Features + + + + + + Enable Timeline editor + + + + + + From bc35583099ee728b3d7babb7016c66a4246dafb5 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 20 Feb 2019 17:35:03 +0100 Subject: [PATCH 38/80] Debugger: Fix resizing of main perspective switcher combo In case of debugger sub-perspectives this was effectively operating on the names of the subperspective, not the "Debugger" string. Change-Id: Ia5c3ea564b2b1a3ed3291d3cb6bae18e1fb5533f Reviewed-by: Eike Ziller --- src/plugins/debugger/debuggermainwindow.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/debuggermainwindow.cpp b/src/plugins/debugger/debuggermainwindow.cpp index c177b3ffcaa..641b6a7f058 100644 --- a/src/plugins/debugger/debuggermainwindow.cpp +++ b/src/plugins/debugger/debuggermainwindow.cpp @@ -119,6 +119,7 @@ public: void resetCurrentPerspective(); int indexInChooser(Perspective *perspective) const; void fixupLayoutIfNeeded(); + void updatePerspectiveChooserWidth(); DebuggerMainWindow *q = nullptr; Perspective *m_currentPerspective = nullptr; @@ -416,10 +417,17 @@ void DebuggerMainWindowPrivate::selectPerspective(Perspective *perspective) fixupLayoutIfNeeded(); } + updatePerspectiveChooserWidth(); +} + +void DebuggerMainWindowPrivate::updatePerspectiveChooserWidth() +{ + Perspective *perspective = m_currentPerspective; int index = indexInChooser(m_currentPerspective); if (index == -1) { - if (Perspective *parent = Perspective::findPerspective(m_currentPerspective->d->m_parentPerspectiveId)) - index = indexInChooser(parent); + perspective = Perspective::findPerspective(m_currentPerspective->d->m_parentPerspectiveId); + if (perspective) + index = indexInChooser(perspective); } if (index != -1) { From 15a0f9d14bcfcead7d778cc11c942279c2c7e7e7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 31 Jan 2019 14:54:04 +0100 Subject: [PATCH 39/80] Add flake2tasks.py for converting output of the flake8 Python linter into task files Change-Id: I85462c9323aaac91076f5025a761a9d1fb7208e4 Reviewed-by: Cristian Maureira-Fredes --- scripts/flake2tasks.py | 50 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100755 scripts/flake2tasks.py diff --git a/scripts/flake2tasks.py b/scripts/flake2tasks.py new file mode 100755 index 00000000000..a98cbf69ec8 --- /dev/null +++ b/scripts/flake2tasks.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +############################################################################ +# +# Copyright (C) 2019 The Qt Company Ltd. +# Contact: https://www.qt.io/licensing/ +# +# This file is part of Qt Creator. +# +# Commercial License Usage +# Licensees holding valid commercial Qt licenses may use this file in +# accordance with the commercial license agreement provided with the +# Software or, alternatively, in accordance with the terms contained in +# a written agreement between you and The Qt Company. For licensing terms +# and conditions see https://www.qt.io/terms-conditions. For further +# information use the contact form at https://www.qt.io/contact-us. +# +# GNU General Public License Usage +# Alternatively, this file may be used under the terms of the GNU +# General Public License version 3 as published by the Free Software +# Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +# included in the packaging of this file. Please review the following +# information to ensure the GNU General Public License requirements will +# be met: https://www.gnu.org/licenses/gpl-3.0.html. +# +############################################################################ + +''' +flake2tasks.py - Convert flake8 warnings into Qt Creator task files. + +SYNOPSIS + + flake2tasks.py < logfile > taskfile +''' + +import sys +import re + +if __name__ == '__main__': + pattern = re.compile(r'^([^:]+):(\d+):\d+: E\d+ (.*)$') + while True: + line = sys.stdin.readline().rstrip() + if not line: + break + match = pattern.match(line) + if match: + file_name = match.group(1).replace('\\', '/') + line_number = match.group(2) + text = match.group(3) + output = "{}\t{}\twarn\t{}".format(file_name, line_number, text) + print(output) From 792fe95c00837674777859debcc01c6c13681d79 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 7 Mar 2019 10:03:09 +0100 Subject: [PATCH 40/80] TextEditor: Fix matching parenthesis highlight reggression The update to the new KSyntaxHighlight engine was missing the matching parenthesis highlight that was implemented in the generic highligter. Fixes: QTCREATORBUG-22095 Change-Id: Ibac0f0739b4e1df63aadf0f18f1b76873e63a2fc Reviewed-by: Eike Ziller --- src/plugins/texteditor/highlighter.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/plugins/texteditor/highlighter.cpp b/src/plugins/texteditor/highlighter.cpp index 4178dc7195f..bbd19d28353 100644 --- a/src/plugins/texteditor/highlighter.cpp +++ b/src/plugins/texteditor/highlighter.cpp @@ -258,6 +258,16 @@ void Highlighter::handleShutdown() delete highlightRepository(); } +static bool isOpeningParenthesis(QChar c) +{ + return c == QLatin1Char('{') || c == QLatin1Char('[') || c == QLatin1Char('('); +} + +static bool isClosingParenthesis(QChar c) +{ + return c == QLatin1Char('}') || c == QLatin1Char(']') || c == QLatin1Char(')'); +} + void Highlighter::highlightBlock(const QString &text) { if (!definition().isValid()) @@ -266,6 +276,18 @@ void Highlighter::highlightBlock(const QString &text) KSyntaxHighlighting::State state = TextDocumentLayout::userData(block)->syntaxState(); state = highlightLine(text, state); block = block.next(); + + Parentheses parentheses; + int pos = 0; + for (const QChar &c : text) { + if (isOpeningParenthesis(c)) + parentheses.push_back(Parenthesis(Parenthesis::Opened, c, pos)); + else if (isClosingParenthesis(c)) + parentheses.push_back(Parenthesis(Parenthesis::Closed, c, pos)); + pos++; + } + TextDocumentLayout::setParentheses(currentBlock(), parentheses); + if (block.isValid()) TextDocumentLayout::userData(block)->setSyntaxState(state); } From 243ba8d3711ea813f0e32d570def7753b93a0131 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 7 Mar 2019 11:35:57 +0100 Subject: [PATCH 41/80] ClangFormat: Add context menu item to open current config file Add the context menu item to C++ editor which allow you to open the currently used .clang-format configuration file. Change-Id: If9d6bec4f4085c18b13df15d78417aee82ddb4e4 Reviewed-by: Marco Bubke Reviewed-by: Leena Miettinen --- .../clangformat/clangformatconstants.h | 1 + src/plugins/clangformat/clangformatplugin.cpp | 55 ++++++++++++++++++- src/plugins/clangformat/clangformatutils.cpp | 5 ++ src/plugins/clangformat/clangformatutils.h | 1 + 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangformat/clangformatconstants.h b/src/plugins/clangformat/clangformatconstants.h index 65ea9b6e81f..2635dbedeac 100644 --- a/src/plugins/clangformat/clangformatconstants.h +++ b/src/plugins/clangformat/clangformatconstants.h @@ -35,5 +35,6 @@ static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeIn static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; static const char OVERRIDE_FILE_ID[] = "ClangFormat.OverrideFile"; +static const char OPEN_CURRENT_CONFIG_ID[] = "ClangFormat.OpenCurrentConfig"; } // namespace Constants } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatplugin.cpp b/src/plugins/clangformat/clangformatplugin.cpp index d1251c75f22..fe381a11818 100644 --- a/src/plugins/clangformat/clangformatplugin.cpp +++ b/src/plugins/clangformat/clangformatplugin.cpp @@ -26,16 +26,23 @@ #include "clangformatplugin.h" #include "clangformatconfigwidget.h" +#include "clangformatconstants.h" #include "clangformatindenter.h" +#include "clangformatutils.h" #include -#include -#include +#include #include #include -#include #include +#include +#include +#include +#include +#include + +#include #include #include @@ -106,6 +113,48 @@ bool ClangFormatPlugin::initialize(const QStringList &arguments, QString *errorS Q_UNUSED(errorString); #ifdef KEEP_LINE_BREAKS_FOR_NON_EMPTY_LINES_BACKPORTED replaceCppCodeStyle(); + + Core::ActionContainer *contextMenu = Core::ActionManager::actionContainer( + CppEditor::Constants::M_CONTEXT); + if (contextMenu) { + auto openClangFormatConfigAction + = new QAction(tr("Open Used .clang-format Configuration File"), this); + Core::Command *command + = Core::ActionManager::registerAction(openClangFormatConfigAction, + Constants::OPEN_CURRENT_CONFIG_ID); + contextMenu->addSeparator(); + contextMenu->addAction(command); + + if (Core::EditorManager::currentEditor()) { + const Core::IDocument *doc = Core::EditorManager::currentEditor()->document(); + if (doc) + openClangFormatConfigAction->setData(doc->filePath().toString()); + } + + connect(openClangFormatConfigAction, + &QAction::triggered, + this, + [openClangFormatConfigAction]() { + const QString fileName = openClangFormatConfigAction->data().toString(); + if (!fileName.isEmpty()) { + const QString clangFormatConfigPath = configForFile( + Utils::FileName::fromString(fileName)); + Core::EditorManager::openEditor(clangFormatConfigPath); + } + }); + + connect(Core::EditorManager::instance(), + &Core::EditorManager::currentEditorChanged, + this, + [openClangFormatConfigAction](Core::IEditor *editor) { + if (!editor) + return; + + const Core::IDocument *doc = editor->document(); + if (doc) + openClangFormatConfigAction->setData(doc->filePath().toString()); + }); + } #endif return true; } diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index bfe0e43cfd6..ad26df413f1 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -163,6 +163,11 @@ static QString configForFile(Utils::FileName fileName, bool checkForSettings) return findConfig(fileName); } +QString configForFile(Utils::FileName fileName) +{ + return configForFile(fileName, true); +} + static clang::format::FormatStyle constructStyle(bool isGlobal, const QByteArray &baseStyle = QByteArray()) { diff --git a/src/plugins/clangformat/clangformatutils.h b/src/plugins/clangformat/clangformatutils.h index 2c818ffe6aa..bd530769430 100644 --- a/src/plugins/clangformat/clangformatutils.h +++ b/src/plugins/clangformat/clangformatutils.h @@ -44,6 +44,7 @@ clang::format::FormatStyle currentProjectStyle(); clang::format::FormatStyle currentGlobalStyle(); // Is the style from the matching .clang-format file or global one if it's not found. +QString configForFile(Utils::FileName fileName); clang::format::FormatStyle styleForFile(Utils::FileName fileName); } From 42c640527af9cbf54a068266554d2daee6430d80 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Thu, 7 Mar 2019 12:31:16 +0100 Subject: [PATCH 42/80] Timeline Editor: Remove invisible translated strings Change-Id: I74d20df6046bbac4ad5ae68111fa0edcd4d04d02 Reviewed-by: Thomas Hartmann --- .../timelineeditor/timelineanimationform.ui | 3 --- .../qmldesignerextension/timelineeditor/timelineform.ui | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui index a27f10f4acd..5d13cfa7264 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineanimationform.ui @@ -10,9 +10,6 @@ 176 - - Form - diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui index 4f063de02da..b8b47e4c701 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelineform.ui @@ -10,9 +10,6 @@ 170 - - Form - From 7570fa16872e5fbc3476e669a426d2427a99aeac Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Thu, 7 Mar 2019 12:20:52 +0100 Subject: [PATCH 43/80] PerfProfiler: Remove misplaced white space Change-Id: I3627bb4b82e448ca658a7bca014ce23e6ec55cf2 Reviewed-by: Leena Miettinen --- src/plugins/perfprofiler/perftracepointdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/perfprofiler/perftracepointdialog.cpp b/src/plugins/perfprofiler/perftracepointdialog.cpp index f42ec8a9a7a..f4eef92c9bb 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.cpp +++ b/src/plugins/perfprofiler/perftracepointdialog.cpp @@ -92,7 +92,7 @@ PerfTracePointDialog::~PerfTracePointDialog() void PerfTracePointDialog::runScript() { - m_ui->label->setText(tr("Executing script ...")); + m_ui->label->setText(tr("Executing script...")); m_ui->textEdit->setReadOnly(true); m_ui->privilegesChooser->setEnabled(false); m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); From 7ce0fc567a449677d0dd48e0e4e76a57332a290a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Wed, 6 Mar 2019 13:39:10 +0100 Subject: [PATCH 44/80] Fix collapsed state when opening file while Projects mode is open The editor manager switches to edit mode when opening a file while a mode without an editor area is open. Project explorer saves settings when the mode is switched away from Projects mode, but did that before the editor's state was restored by the editor manager. Settings saving should not be done while transitioning states, so delay that to a clean, next event loop processing. Fixes: QTCREATORBUG-16982 Change-Id: I165ed2f84611f45341f81d24a12dc257e208ef1f Reviewed-by: Christian Kandeler --- src/plugins/projectexplorer/projectexplorer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index eebd7c91ed1..d458c6bd7f8 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -2058,8 +2058,12 @@ void ProjectExplorerPluginPrivate::updateWelcomePage() void ProjectExplorerPluginPrivate::currentModeChanged(Id mode, Id oldMode) { - if (oldMode == Constants::MODE_SESSION) - ICore::saveSettings(); + if (oldMode == Constants::MODE_SESSION) { + // Saving settings directly in a mode change is not a good idea, since the mode change + // can be part of a bigger change. Save settings after that bigger change had a chance to + // complete. + QTimer::singleShot(0, ICore::instance(), &ICore::saveSettings); + } if (mode == Core::Constants::MODE_WELCOME) updateWelcomePage(); } From df23fbdc8931055d43b9665682e4562a81ead4f7 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 7 Mar 2019 12:29:10 +0100 Subject: [PATCH 45/80] ClangFormat: Improve dummy text guessing for empty lines Improve detection of the cases when the empty line is inside the parenthesis to get more proper indentation. Change-Id: I4aa37c29b17bedcd0e4a781d12c7066e818a07f3 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 70 +++++++++++++++---- tests/unit/unittest/clangformat-test.cpp | 13 ++++ 2 files changed, 68 insertions(+), 15 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 7f47b418a77..83e877259c9 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -127,6 +127,44 @@ void trimRHSWhitespace(const QTextBlock &block) cursor.endEditBlock(); } +// We don't need other types so far. +enum class CharacterType { OpeningParen, OpeningBrace, Invalid }; + +CharacterType firstOpeningParenOrBraceBeforeBlock(const QTextBlock &block) +{ + if (block.text().trimmed().startsWith(')')) + return CharacterType::OpeningParen; + + QTextCursor cursor(block); + const QTextDocument *doc = block.document(); + + cursor.movePosition(QTextCursor::PreviousCharacter); + QChar currentChar = doc->characterAt(cursor.position()); + + int parenCount = 0; + int braceCount = 0; + + while (cursor.position() > 0 && parenCount <= 0 && braceCount <= 0) { + cursor.movePosition(QTextCursor::PreviousCharacter); + currentChar = doc->characterAt(cursor.position()); + if (currentChar == '(') + ++parenCount; + else if (currentChar == ')') + --parenCount; + else if (currentChar == '{') + ++braceCount; + else if (currentChar == '}') + --braceCount; + } + + if (braceCount > 0) + return CharacterType::OpeningBrace; + if (parenCount > 0) + return CharacterType::OpeningParen; + + return CharacterType::Invalid; +} + // Add extra text in case of the empty line or the line starting with ')'. // Track such extra pieces of text in isInsideModifiedLine(). int forceIndentWithExtraText(QByteArray &buffer, @@ -147,25 +185,27 @@ int forceIndentWithExtraText(QByteArray &buffer, const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; + int extraLength = 0; if (firstNonWhitespace < 0 || closingParenBlock) { if (dummyText.isEmpty()) { + const CharacterType charType = firstOpeningParenOrBraceBeforeBlock(block); // If we don't know yet the dummy text, let's guess it and use for this line and before. - // This extra text works for the most cases. - dummyText = "a;a;"; - - // Search for previous character - QTextBlock prevBlock = block.previous(); - bool prevBlockIsEmpty = prevBlock.position() > 0 - && prevBlock.text().trimmed().isEmpty(); - while (prevBlockIsEmpty) { - prevBlock = prevBlock.previous(); - prevBlockIsEmpty = prevBlock.position() > 0 && prevBlock.text().trimmed().isEmpty(); + if (charType != CharacterType::OpeningParen) { + // Use the complete statement if we are not inside parenthesis. + dummyText = "a;a;"; + } else { + // Search for previous character + QTextBlock prevBlock = block.previous(); + bool prevBlockIsEmpty = prevBlock.position() > 0 + && prevBlock.text().trimmed().isEmpty(); + while (prevBlockIsEmpty) { + prevBlock = prevBlock.previous(); + prevBlockIsEmpty = prevBlock.position() > 0 + && prevBlock.text().trimmed().isEmpty(); + } + dummyText = prevBlock.text().endsWith(',') ? "&& a," : "&& a"; } - if (prevBlock.text().endsWith(',')) - dummyText = "&& a,"; - else if (closingParenBlock) - dummyText = "&& a"; } buffer.insert(utf8Offset, dummyText); @@ -179,7 +219,7 @@ int forceIndentWithExtraText(QByteArray &buffer, if (nextLinePos > 0) { // If first try was not successful try to put ')' in the end of the line to close possibly - // unclosed parentheses. + // unclosed parenthesis. // TODO: Does it help to add different endings depending on the context? buffer.insert(nextLinePos, ')'); extraLength += 1; diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 43380c85028..f87bb1dc747 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -391,6 +391,19 @@ TEST_F(ClangFormat, IndentAfterExtraSpaceInpreviousLine) " && b)")); } +TEST_F(ClangFormat, IndentEmptyLineInsideParantheses) +{ + insertLines({"if (a ", + "", + " && b)"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a", + " ", + " && b)")); +} + TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", From 40fcc728b240ed5d4ad93de588537dd48d284183 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Thu, 7 Mar 2019 13:45:22 +0100 Subject: [PATCH 46/80] ClangFormat: Use by default the same style as Qt Creator uses Change-Id: Iae0f774873f66fcd4e297cfc260a8541f4373e36 Reviewed-by: Marco Bubke --- .clang-format | 2 + src/plugins/clangformat/clangformatutils.cpp | 155 +++++++++++++------ 2 files changed, 106 insertions(+), 51 deletions(-) diff --git a/.clang-format b/.clang-format index 953e0b44cd6..97f7f2b2347 100644 --- a/.clang-format +++ b/.clang-format @@ -8,6 +8,8 @@ # Use ../../tests/manual/clang-format-for-qtc/test.cpp for documenting problems # or testing changes. # +# In case you update this configuration please also update the qtcStyle() in src\plugins\clangformat\clangformatutils.cpp +# # [1] https://doc-snapshots.qt.io/qtcreator-extending/coding-style.html # [2] https://clang.llvm.org/docs/ClangFormatStyleOptions.html # diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index ad26df413f1..45ed4feacf1 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -45,6 +45,104 @@ using namespace TextEditor; namespace ClangFormat { +static clang::format::FormatStyle qtcStyle() +{ + clang::format::FormatStyle style = getLLVMStyle(); + style.Language = FormatStyle::LK_Cpp; + style.AccessModifierOffset = -4; + style.AlignAfterOpenBracket = FormatStyle::BAS_Align; + style.AlignConsecutiveAssignments = false; + style.AlignConsecutiveDeclarations = false; + style.AlignEscapedNewlines = FormatStyle::ENAS_DontAlign; + style.AlignOperands = true; + style.AlignTrailingComments = true; + style.AllowAllParametersOfDeclarationOnNextLine = true; + style.AllowShortBlocksOnASingleLine = false; + style.AllowShortCaseLabelsOnASingleLine = false; + style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline; + style.AllowShortIfStatementsOnASingleLine = false; + style.AllowShortLoopsOnASingleLine = false; + style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None; + style.AlwaysBreakBeforeMultilineStrings = false; + style.AlwaysBreakTemplateDeclarations = FormatStyle::BTDS_Yes; + style.BinPackArguments = false; + style.BinPackParameters = false; + style.BraceWrapping.AfterClass = true; + style.BraceWrapping.AfterControlStatement = false; + style.BraceWrapping.AfterEnum = false; + style.BraceWrapping.AfterFunction = true; + style.BraceWrapping.AfterNamespace = false; + style.BraceWrapping.AfterObjCDeclaration = false; + style.BraceWrapping.AfterStruct = true; + style.BraceWrapping.AfterUnion = false; + style.BraceWrapping.BeforeCatch = false; + style.BraceWrapping.BeforeElse = false; + style.BraceWrapping.IndentBraces = false; + style.BraceWrapping.SplitEmptyFunction = false; + style.BraceWrapping.SplitEmptyRecord = false; + style.BraceWrapping.SplitEmptyNamespace = false; + style.BreakBeforeBinaryOperators = FormatStyle::BOS_All; + style.BreakBeforeBraces = FormatStyle::BS_Custom; + style.BreakBeforeTernaryOperators = true; + style.BreakConstructorInitializers = FormatStyle::BCIS_BeforeComma; + style.BreakAfterJavaFieldAnnotations = false; + style.BreakStringLiterals = true; + style.ColumnLimit = 100; + style.CommentPragmas = "^ IWYU pragma:"; + style.CompactNamespaces = false; + style.ConstructorInitializerAllOnOneLineOrOnePerLine = false; + style.ConstructorInitializerIndentWidth = 4; + style.ContinuationIndentWidth = 4; + style.Cpp11BracedListStyle = true; + style.DerivePointerAlignment = false; + style.DisableFormat = false; + style.ExperimentalAutoDetectBinPacking = false; + style.FixNamespaceComments = true; + style.ForEachMacros = {"forever", "foreach", "Q_FOREACH", "BOOST_FOREACH"}; + style.IncludeStyle.IncludeCategories = {{"^(settings.m_indentSize); @@ -66,35 +164,6 @@ static void applyTabSettings(clang::format::FormatStyle &style, const TabSetting } } -static void applyCppCodeStyleSettings(clang::format::FormatStyle &style, - const CppCodeStyleSettings &settings) -{ - style.IndentCaseLabels = settings.indentSwitchLabels; - style.AlignOperands = settings.alignAssignments; - style.NamespaceIndentation = FormatStyle::NI_None; - if (settings.indentNamespaceBody) - style.NamespaceIndentation = FormatStyle::NI_All; - - style.BraceWrapping.IndentBraces = false; - if (settings.indentBlockBraces) { - if (settings.indentClassBraces && settings.indentEnumBraces - && settings.indentNamespaceBraces && settings.indentFunctionBraces) { - style.BraceWrapping.IndentBraces = true; - } else { - style.BreakBeforeBraces = FormatStyle::BS_GNU; - } - } - - if (settings.bindStarToIdentifier || settings.bindStarToRightSpecifier) - style.PointerAlignment = FormatStyle::PAS_Right; - else - style.PointerAlignment = FormatStyle::PAS_Left; - - style.AccessModifierOffset = settings.indentAccessSpecifiers - ? 0 - : - static_cast(style.IndentWidth); -} - static bool useGlobalOverriddenSettings() { return ClangFormatSettings::instance().overrideDefaultFile(); @@ -168,8 +237,7 @@ QString configForFile(Utils::FileName fileName) return configForFile(fileName, true); } -static clang::format::FormatStyle constructStyle(bool isGlobal, - const QByteArray &baseStyle = QByteArray()) +static clang::format::FormatStyle constructStyle(const QByteArray &baseStyle = QByteArray()) { if (!baseStyle.isEmpty()) { // Try to get the style for this base style. @@ -185,21 +253,7 @@ static clang::format::FormatStyle constructStyle(bool isGlobal, // Fallthrough to the default style. } - FormatStyle style = getLLVMStyle(); - style.BreakBeforeBraces = FormatStyle::BS_Custom; - - const CppCodeStyleSettings codeStyleSettings = isGlobal - ? CppCodeStyleSettings::currentGlobalCodeStyle() - : CppCodeStyleSettings::currentProjectCodeStyle() - .value_or(CppCodeStyleSettings::currentGlobalCodeStyle()); - const TabSettings tabSettings = isGlobal - ? CppCodeStyleSettings::currentGlobalTabSettings() - : CppCodeStyleSettings::currentProjectTabSettings(); - - applyTabSettings(style, tabSettings); - applyCppCodeStyleSettings(style, codeStyleSettings); - - return style; + return qtcStyle(); } void createStyleFileIfNeeded(bool isGlobal) @@ -224,7 +278,7 @@ void createStyleFileIfNeeded(bool isGlobal) std::fstream newStyleFile(configFile.toStdString(), std::fstream::out); if (newStyleFile.is_open()) { - newStyleFile << clang::format::configurationAsText(constructStyle(isGlobal)); + newStyleFile << clang::format::configurationAsText(constructStyle()); newStyleFile.close(); } } @@ -255,7 +309,7 @@ static clang::format::FormatStyle styleForFile(Utils::FileName fileName, bool ch { QString configFile = configForFile(fileName, checkForSettings); if (configFile.isEmpty()) - return constructStyle(true); + return constructStyle(); Expected style = format::getStyle("file", fileName.toString().toStdString(), @@ -267,7 +321,7 @@ static clang::format::FormatStyle styleForFile(Utils::FileName fileName, bool ch // do nothing }); - return constructStyle(true, configBaseStyleName(configFile)); + return constructStyle(configBaseStyleName(configFile)); } clang::format::FormatStyle styleForFile(Utils::FileName fileName) @@ -284,5 +338,4 @@ clang::format::FormatStyle currentGlobalStyle() { return styleForFile(globalPath().appendPath(Constants::SAMPLE_FILE_NAME), false); } - -} +} // namespace ClangFormat From d35af1c1bb75a7db862e4b1a8fb2ee1821020150 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Thu, 7 Mar 2019 13:33:14 +0100 Subject: [PATCH 47/80] Utils: Use proper plural Change-Id: Ia1b596aa373fdc5629a1d164b7df63992f1f3dc8 Reviewed-by: Leena Miettinen Reviewed-by: David Schulz --- src/libs/utils/jsontreeitem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/jsontreeitem.cpp b/src/libs/utils/jsontreeitem.cpp index a70f5631ec8..16da8e803e6 100644 --- a/src/libs/utils/jsontreeitem.cpp +++ b/src/libs/utils/jsontreeitem.cpp @@ -63,9 +63,9 @@ QVariant Utils::JsonTreeItem::data(int column, int role) const if (column == 2) return typeName(m_value.type()); if (m_value.isObject()) - return QString('[' + QString::number(m_value.toObject().size()) + ' ' + tr("Items") + ']'); + return QString('[' + tr("%n Items", nullptr, m_value.toObject().size()) + ']'); if (m_value.isArray()) - return QString('[' + QString::number(m_value.toArray().size()) + ' ' + tr("Items") + ']'); + return QString('[' + tr("%n Items", nullptr, m_value.toArray().size()) + ']'); return m_value.toVariant(); } From c9e13a18a3ecd534326614fadc0d8158997245a9 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 28 Feb 2019 14:49:34 +0100 Subject: [PATCH 48/80] Output pane manager: Fix two inconsistencies 1) Currently deselected panes that popped up due to some event behaved differently with respect to their button visibility: For instance, if the user hides the application output pane and then new application output arrives (and the respective item in the "Build & Run" settings is enabled), then the pane widget would appear as well as the pane button. In contrast, for the issues pane only the widget itself would appear, but the button was still hidden. Now the button appears along with the widget for all output panes. 2) When the deselected app output pane popped up due to new output (as described above), then the check button in the output pane menu failed to update, i.e. was still unchecked and thus inconsistent with the actual state. Now it is in sync. Change-Id: I5e100363c6c01327b2c03b7f22ca173d41d13d7c Reviewed-by: Eike Ziller --- src/plugins/coreplugin/outputpanemanager.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp index bda60b58123..7825126565c 100644 --- a/src/plugins/coreplugin/outputpanemanager.cpp +++ b/src/plugins/coreplugin/outputpanemanager.cpp @@ -507,7 +507,6 @@ void OutputPaneManager::showPage(int idx, int flags) ensurePageVisible(idx); IOutputPane *out = g_outputPanes.at(idx).pane; - out->visibilityChanged(true); if (flags & IOutputPane::WithFocus) { if (out->canFocus()) out->setFocus(); @@ -538,7 +537,10 @@ void OutputPaneManager::setCurrentIndex(int idx) m_outputWidgetPane->setCurrentIndex(idx); m_opToolBarWidgets->setCurrentIndex(idx); - IOutputPane *pane = g_outputPanes.at(idx).pane; + OutputPaneData &data = g_outputPanes[idx]; + IOutputPane *pane = data.pane; + data.button->show(); + data.buttonVisible = true; pane->visibilityChanged(true); bool canNavigate = pane->canNavigate(); @@ -574,8 +576,6 @@ void OutputPaneManager::popupMenu() data.button->hide(); data.buttonVisible = false; } else { - data.button->show(); - data.buttonVisible = true; showPage(idx, IOutputPane::ModeSwitch); } } From b7375aabfb3d0b418553953f03c2e713de8e6e0b Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Thu, 7 Mar 2019 13:26:26 +0100 Subject: [PATCH 49/80] SSH: Fix error message A binary cannot crash. When executing the binary, a process is created which can crash. Change-Id: I0dc3d41c84b55fefda7e98353390b49bb51a288f Reviewed-by: Christian Kandeler --- src/libs/ssh/sshremoteprocess.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp index aa46214afbb..4bd09b37e1f 100644 --- a/src/libs/ssh/sshremoteprocess.cpp +++ b/src/libs/ssh/sshremoteprocess.cpp @@ -71,7 +71,7 @@ SshRemoteProcess::SshRemoteProcess(const QByteArray &command, const QStringList [this] { QString error; if (exitStatus() == QProcess::CrashExit) - error = tr("The ssh binary crashed: %1").arg(errorString()); + error = tr("The ssh process crashed: %1").arg(errorString()); else if (exitCode() == 255) error = tr("Remote process crashed."); emit done(error); From 37eb282313783e2b9834fedf12ad14d23581b067 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 7 Mar 2019 15:13:26 +0100 Subject: [PATCH 50/80] qmljs: Fix variable name Change-Id: I8ea8d18e0471071f3a7a22760c041ecf77dbbe8c Reviewed-by: Alessandro Portale --- src/libs/qmljs/qmljscheck.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index 3a58bffd397..38a98c74f9f 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -753,8 +753,8 @@ void Check::endVisit(UiObjectInitializer *) { m_propertyStack.pop(); m_typeStack.pop(); - UiObjectDefinition *objectDenition = cast(parent()); - if (objectDenition && objectDenition->qualifiedTypeNameId->name == QLatin1String("Component")) + UiObjectDefinition *objectDefinition = cast(parent()); + if (objectDefinition && objectDefinition->qualifiedTypeNameId->name == QLatin1String("Component")) m_idStack.pop(); UiObjectBinding *objectBinding = cast(parent()); if (objectBinding && objectBinding->qualifiedTypeNameId->name == QLatin1String("Component")) From 2d3e8ef77b7b69a806343758a0047024e67f0761 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 7 Mar 2019 14:48:28 +0100 Subject: [PATCH 51/80] Windows: Fix missing debug info for qtcreator executable When we set a VERSION, there is QTBUG-74265 which leads to wrong rules for the pdb file. On Windows we do not really need the VERSION for the qtcreator executable (we create an .rc file for the executable details for Windows), so unset the VERSION that is set in qtcreator.pri on Windows. Change-Id: I1e0289fe027b48560ec71f6df70522174770fe84 Reviewed-by: Joerg Bornemann --- src/app/app.pro | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/app.pro b/src/app/app.pro index 89b9554a9ff..712563419e6 100644 --- a/src/app/app.pro +++ b/src/app/app.pro @@ -5,8 +5,9 @@ TEMPLATE = app CONFIG += qtc_runnable sliced_bundle TARGET = $$IDE_APP_TARGET DESTDIR = $$IDE_APP_PATH -VERSION = $$QTCREATOR_VERSION QT -= testlib +# work around QTBUG-74265 +win32: VERSION= HEADERS += ../tools/qtcreatorcrashhandler/crashhandlersetup.h SOURCES += main.cpp ../tools/qtcreatorcrashhandler/crashhandlersetup.cpp From 5006bfb1572c64da2ac3d5104074c50cbdfa785a Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 11 Mar 2019 11:10:12 +0100 Subject: [PATCH 52/80] ClangFormat: Simplify the dummy text for empty line heuristics The text to fill the empty line mostly depends not on the fact of being inside parenthesis or not but rather on the last preceding meaningful character. Let's check for this character and sometimes for the following one to better understand the current context and pick the proper dummy text. With this behavior improvement we can better indent empty lines inside initializer lists with empty lines inside. Change-Id: Id2f27454ef56dfdf8c15b5efb14c4d09242908a9 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 113 ++++++++---------- tests/unit/unittest/clangformat-test.cpp | 13 ++ 2 files changed, 65 insertions(+), 61 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 83e877259c9..bdf384863ab 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -127,48 +127,51 @@ void trimRHSWhitespace(const QTextBlock &block) cursor.endEditBlock(); } -// We don't need other types so far. -enum class CharacterType { OpeningParen, OpeningBrace, Invalid }; - -CharacterType firstOpeningParenOrBraceBeforeBlock(const QTextBlock &block) +QTextBlock reverseFindLastEmptyBlock(QTextBlock start) { - if (block.text().trimmed().startsWith(')')) - return CharacterType::OpeningParen; + if (start.position() > 0) { + start = start.previous(); + while (start.position() > 0 && start.text().trimmed().isEmpty()) + start = start.previous(); + if (!start.text().trimmed().isEmpty()) + start = start.next(); + } + return start; +} - QTextCursor cursor(block); - const QTextDocument *doc = block.document(); +enum class CharacterContext { AfterComma, LastAfterComma, NewStatement, Continuation, Unknown }; - cursor.movePosition(QTextCursor::PreviousCharacter); - QChar currentChar = doc->characterAt(cursor.position()); +QChar findFirstNonWhitespaceCharacter(const QTextBlock ¤tBlock) +{ + const QTextDocument *doc = currentBlock.document(); + int currentPos = currentBlock.position(); + while (currentPos < doc->characterCount() && doc->characterAt(currentPos).isSpace()) + ++currentPos; + return currentPos < doc->characterCount() ? doc->characterAt(currentPos) : QChar::Null; +} - int parenCount = 0; - int braceCount = 0; - - while (cursor.position() > 0 && parenCount <= 0 && braceCount <= 0) { - cursor.movePosition(QTextCursor::PreviousCharacter); - currentChar = doc->characterAt(cursor.position()); - if (currentChar == '(') - ++parenCount; - else if (currentChar == ')') - --parenCount; - else if (currentChar == '{') - ++braceCount; - else if (currentChar == '}') - --braceCount; +CharacterContext characterContext(const QTextBlock ¤tBlock, + const QTextBlock &previousNonEmptyBlock) +{ + const QString prevLineText = previousNonEmptyBlock.text().trimmed(); + if (prevLineText.endsWith(',')) { + const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock); + // We don't need to add comma in case it's the last argument. + if (firstNonWhitespaceChar == '}' || firstNonWhitespaceChar == ')') + return CharacterContext::LastAfterComma; + return CharacterContext::AfterComma; } - if (braceCount > 0) - return CharacterType::OpeningBrace; - if (parenCount > 0) - return CharacterType::OpeningParen; + if (prevLineText.endsWith(';') || prevLineText.endsWith('{') || prevLineText.endsWith('}')) + return CharacterContext::NewStatement; - return CharacterType::Invalid; + return CharacterContext::Continuation; } // Add extra text in case of the empty line or the line starting with ')'. // Track such extra pieces of text in isInsideModifiedLine(). int forceIndentWithExtraText(QByteArray &buffer, - QByteArray &dummyText, + CharacterContext &charContext, const QTextBlock &block, bool secondTry) { @@ -188,24 +191,24 @@ int forceIndentWithExtraText(QByteArray &buffer, int extraLength = 0; if (firstNonWhitespace < 0 || closingParenBlock) { - if (dummyText.isEmpty()) { - const CharacterType charType = firstOpeningParenOrBraceBeforeBlock(block); + if (charContext == CharacterContext::LastAfterComma) { + charContext = CharacterContext::AfterComma; + } else if (charContext == CharacterContext::Unknown) { + QTextBlock lastBlock = reverseFindLastEmptyBlock(block); + if (lastBlock.position() > 0) + lastBlock = lastBlock.previous(); + // If we don't know yet the dummy text, let's guess it and use for this line and before. - if (charType != CharacterType::OpeningParen) { - // Use the complete statement if we are not inside parenthesis. - dummyText = "a;a;"; - } else { - // Search for previous character - QTextBlock prevBlock = block.previous(); - bool prevBlockIsEmpty = prevBlock.position() > 0 - && prevBlock.text().trimmed().isEmpty(); - while (prevBlockIsEmpty) { - prevBlock = prevBlock.previous(); - prevBlockIsEmpty = prevBlock.position() > 0 - && prevBlock.text().trimmed().isEmpty(); - } - dummyText = prevBlock.text().endsWith(',') ? "&& a," : "&& a"; - } + charContext = characterContext(block, lastBlock); + } + + QByteArray dummyText; + if (charContext == CharacterContext::NewStatement) { + dummyText = "a;a;"; + } else if (charContext == CharacterContext::AfterComma) { + dummyText = "&& a,"; + } else { + dummyText = "&& a"; } buffer.insert(utf8Offset, dummyText); @@ -349,18 +352,6 @@ bool doNotIndentInContext(QTextDocument *doc, int pos) return false; } -QTextBlock reverseFindLastEmptyBlock(QTextBlock start) -{ - if (start.position() > 0) { - start = start.previous(); - while (start.position() > 0 && start.text().trimmed().isEmpty()) - start = start.previous(); - if (!start.text().trimmed().isEmpty()) - start = start.next(); - } - return start; -} - int formattingRangeStart(const QTextBlock ¤tBlock, const QByteArray &buffer, int documentRevision) @@ -405,11 +396,11 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer adjustFormatStyleForLineBreak(style, replacementsToKeep); if (replacementsToKeep == ReplacementsToKeep::OnlyIndent) { - QByteArray dummyText; + CharacterContext currentCharContext = CharacterContext::Unknown; // Iterate backwards to reuse the same dummy text for all empty lines. for (int index = endBlock.blockNumber(); index >= startBlock.blockNumber(); --index) { utf8Length += forceIndentWithExtraText(buffer, - dummyText, + currentCharContext, m_doc->findBlockByNumber(index), secondTry); } diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index f87bb1dc747..56b80d9e223 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -404,6 +404,19 @@ TEST_F(ClangFormat, IndentEmptyLineInsideParantheses) " && b)")); } +TEST_F(ClangFormat, EmptyLineInInitializerList) +{ + insertLines({"Bar foo{a,", + "", + "};"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("Bar foo{a,", + " ", + "};")); +} + TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", From d9703158eeb440b34ba6621b1adeaee3f3509844 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 4 Mar 2019 11:07:53 +0100 Subject: [PATCH 53/80] Clang: Fix language version detection with PCH-s in CMake enabled Filter out the PCH flags when detecting macros and language version. Fixes: QTCREATORBUG-21860 Change-Id: I25c63f1409c16db3623d1c8f43ffd5d2bd0f6748 Reviewed-by: David Schulz Reviewed-by: Marco Bubke --- src/plugins/cpptools/compileroptionsbuilder.cpp | 9 +++++++++ src/plugins/projectexplorer/msvctoolchain.cpp | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index e5685dc5e05..f757f2fe2cc 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -741,6 +741,15 @@ void CompilerOptionsBuilder::evaluateCompilerFlags() continue; } + if (option.startsWith("/Y", Qt::CaseSensitive) + || (option.startsWith("/F", Qt::CaseSensitive) && option != "/F")) { + // Precompiled header flags. + // Skip also the next option if it's not glued to the current one. + if (option.size() > 3) + skipNext = true; + continue; + } + // Check whether a language version is already used. QString theOption = option; if (theOption.startsWith("-std=")) { diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 8b8c5711428..9c86a706869 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1027,6 +1027,8 @@ bool static hasFlagEffectOnMacros(const QString &flag) return false; // Skip include paths if (f.startsWith("w", Qt::CaseInsensitive)) return false; // Skip warning options + if (f.startsWith("Y") || (f.startsWith("F") && f != "F")) + return false; // Skip pch-related flags } return true; } From 0852f889d1efbbbb96803a60cc769ecf82c2f9c1 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 11 Mar 2019 12:01:02 +0100 Subject: [PATCH 54/80] Clang: Do not show global completions after comma Handle the case when we try to show the function hint but do not find any completion. Do not fall back to the normal code completion in such case. Fixes: QTCREATORBUG-21624 Change-Id: I147d71b8970c18d49947f68786347a9db97736bb Reviewed-by: Marco Bubke --- .../clangcompletionassistprocessor.cpp | 13 +++++++++++++ .../clangcodemodel/clangcompletionassistprocessor.h | 1 + 2 files changed, 14 insertions(+) diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp index db34c904d46..6f1397c4874 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.cpp @@ -214,6 +214,9 @@ void ClangCompletionAssistProcessor::handleAvailableCompletions(const CodeComple setAsyncProposalAvailable(createFunctionHintProposal(completions)); return; } + + if (!m_fallbackToNormalCompletion) + return; // else: Proceed with a normal completion in case: // 1) it was not a function call, but e.g. a function declaration like "void f(" // 2) '{' meant not a constructor call. @@ -286,6 +289,14 @@ static QByteArray modifyInput(QTextDocument *doc, int endOfExpression) { return modifiedInput; } +static QChar lastPrecedingNonWhitespaceChar(const ClangCompletionAssistInterface *interface) +{ + int pos = interface->position(); + while (pos >= 0 && interface->characterAt(pos).isSpace()) + --pos; + return pos >= 0 ? interface->characterAt(pos) : QChar::Null; +} + IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() { ClangCompletionContextAnalyzer analyzer(m_interface.data(), m_interface->languageFeatures()); @@ -323,6 +334,8 @@ IAssistProposal *ClangCompletionAssistProcessor::startCompletionHelper() } case ClangCompletionContextAnalyzer::PassThroughToLibClangAfterLeftParen: { m_sentRequestType = FunctionHintCompletion; + if (lastPrecedingNonWhitespaceChar(m_interface.data()) == ',') + m_fallbackToNormalCompletion = false; m_requestSent = sendCompletionRequest(analyzer.positionForClang(), QByteArray(), analyzer.functionNameStart()); break; diff --git a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h index 03711f0fa8f..5e8c772235e 100644 --- a/src/plugins/clangcodemodel/clangcompletionassistprocessor.h +++ b/src/plugins/clangcodemodel/clangcompletionassistprocessor.h @@ -97,6 +97,7 @@ private: CompletionRequestType m_sentRequestType = NormalCompletion; bool m_requestSent = false; bool m_addSnippets = false; // For type == Type::NormalCompletion + bool m_fallbackToNormalCompletion = true; }; } // namespace Internal From 694c895ae499ed12bca0ace91278a8afbe81cfe9 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 11 Mar 2019 13:48:25 +0100 Subject: [PATCH 55/80] Clang: Only use llvm-config options starting with '/' or '-' llvm-config does not wrap paths into quotes so there's no way of knowing where the path with spaces ends. As a workaround let's not use options which do not start with '/' or '-' to throw away the remaining parts of such paths. Fixes: QTCREATORBUG-21929 Change-Id: I20afa3ef6e36f19b7a164114c8f0473a9109a74d Reviewed-by: Marco Bubke --- src/shared/clang/clang_installation.pri | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/shared/clang/clang_installation.pri b/src/shared/clang/clang_installation.pri index 6c820dc36d9..8c75b6cc820 100644 --- a/src/shared/clang/clang_installation.pri +++ b/src/shared/clang/clang_installation.pri @@ -96,7 +96,16 @@ defineReplace(splitFlags) { flag ~= s,-I\S*,, flag ~= s,/D\S*,, flag ~= s,/Z\S*,, - result += $$split(flag, " ") + separate_flags = $$split(flag, " ") + for (separate_flag, separate_flags) { + starting_substr = $$str_member($$separate_flag, 0, 0) + win32:equals(starting_substr, "/") { + result += $$separate_flag + } + equals(starting_substr, "-") { + result += $$separate_flag + } + } } else { inside_quotes = 0 starting_substr = $$str_member($$flag, 0, 0) From 10b3da5d3491c7b68fa31509a50ee896d082d24e Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Mon, 11 Mar 2019 14:54:31 +0100 Subject: [PATCH 56/80] PythonEditor: Fix strings Change-Id: Ib48c5b7c5cc56ac8bfe1d0641d595e680faf62e7 Reviewed-by: Friedemann Kleint --- src/plugins/pythoneditor/pythoneditorplugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index 1d6af67381d..c8fbe192c7f 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -364,7 +364,7 @@ static QStringList readLinesJson(const Utils::FileName &projectFile, // This assumes te project file is formed with only one field called // 'files' that has a list associated of the files to include in the project. if (content.isEmpty()) { - *errorMessage = PythonProject::tr("Unable read \"%1\": The file is empty.") + *errorMessage = PythonProject::tr("Unable to read \"%1\": The file is empty.") .arg(projectFile.toUserOutput()); return lines; } @@ -373,7 +373,7 @@ static QStringList readLinesJson(const Utils::FileName &projectFile, const QJsonDocument doc = QJsonDocument::fromJson(content, &error); if (doc.isNull()) { const int line = content.left(error.offset).count('\n') + 1; - *errorMessage = PythonProject::tr("Unable parse %1:%2: %3") + *errorMessage = PythonProject::tr("Unable to parse \"%1\":%2: %3") .arg(projectFile.toUserOutput()).arg(line) .arg(error.errorString()); return lines; From c10aca827e83530609774ab14e0e2dd129a89ac6 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Mon, 11 Mar 2019 14:51:31 +0100 Subject: [PATCH 57/80] QtSupport: Fix autotests The output formatter code normalizes the path separators if the path points to a non-existing file (via FileInProjectFinder), but only on Windows. So expect a normalized path in the result, and only run the Windows-specific test on Windows. Change-Id: Ifef8292a60d8c4f5f94476fb8678d56ac97a9361 Reviewed-by: Christian Stenger --- src/plugins/qtsupport/qtoutputformatter.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/plugins/qtsupport/qtoutputformatter.cpp b/src/plugins/qtsupport/qtoutputformatter.cpp index cb98654858c..84f8e692a14 100644 --- a/src/plugins/qtsupport/qtoutputformatter.cpp +++ b/src/plugins/qtsupport/qtoutputformatter.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -401,16 +402,16 @@ void QtSupportPlugin::testQtOutputFormatter_data() << " Loc: [../TestProject/test.cpp(123)]" << 9 << 37 << "../TestProject/test.cpp(123)" << "../TestProject/test.cpp" << 123 << -1; - - QTest::newRow("Windows failed QTest link") - << "..\\TestProject\\test.cpp(123) : failure location" - << 0 << 28 << "..\\TestProject\\test.cpp(123)" - << "..\\TestProject\\test.cpp" << 123 << -1; - - QTest::newRow("Windows failed QTest link with carriage return") - << "..\\TestProject\\test.cpp(123) : failure location\r" - << 0 << 28 << "..\\TestProject\\test.cpp(123)" - << "..\\TestProject\\test.cpp" << 123 << -1; + if (HostOsInfo::isWindowsHost()) { + QTest::newRow("Windows failed QTest link") + << "..\\TestProject\\test.cpp(123) : failure location" + << 0 << 28 << "..\\TestProject\\test.cpp(123)" + << "../TestProject/test.cpp" << 123 << -1; + QTest::newRow("Windows failed QTest link with carriage return") + << "..\\TestProject\\test.cpp(123) : failure location\r" + << 0 << 28 << "..\\TestProject\\test.cpp(123)" + << "../TestProject/test.cpp" << 123 << -1; + } } void QtSupportPlugin::testQtOutputFormatter() From 1959664210bdaa56452834bc225400bc26d1d2cf Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 11 Mar 2019 11:39:39 +0100 Subject: [PATCH 58/80] Clang: Update LLVM/Clang version in the README Fixes: QTCREATORBUG-22103 Change-Id: Ic83923ded4ad9a91fb189b60ab43ca93426ee9a0 Reviewed-by: Marco Bubke --- README.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 735259eebb9..017b659040c 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,10 @@ Prerequisites: * Python 3.5 or later (optional, needed for the python enabled debug helper) * On Mac OS X: latest Xcode * On Linux: g++ 5.3 or later -* LLVM/Clang 6.0.0 or later (optional, needed for the Clang Code Model, see the - section "Get LLVM/Clang for the Clang Code Model") - * CMake (only for manual builds of LLVM/Clang) +* LLVM/Clang 7.0.0 or later (optional, needed for the Clang Code Model, Clang Tools, ClangFormat, + Clang PCH Manager and Clang Refactoring plugins, see the section + "Get LLVM/Clang for the Clang Code Model") +* CMake (only for manual builds of LLVM/Clang) * Qbs 1.7.x (optional, sources also contain Qbs itself) The installed toolchains have to match the one Qt was compiled with. @@ -224,7 +225,7 @@ or using shadow builds. ## Get LLVM/Clang for the Clang Code Model The Clang Code Model depends on the LLVM/Clang libraries. The currently -supported LLVM/Clang version is 6.0. +supported LLVM/Clang version is 7.0. ### Prebuilt LLVM/Clang packages @@ -251,9 +252,9 @@ GCC 4 binaries. On Ubuntu, you can download the package from http://apt.llvm.org/ with: wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - sudo apt-add-repository "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-6.0 main" + sudo apt-add-repository "deb http://apt.llvm.org/`lsb_release -cs`/ llvm-toolchain-`lsb_release -cs`-7.0 main" sudo apt-get update - sudo apt-get install llvm-6.0 libclang-6.0-dev + sudo apt-get install llvm-7.0 libclang-7.0-dev There is a workaround to set _GLIBCXX_USE_CXX11_ABI to 1 or 0, but we recommend to download the package from http://apt.llvm.org/. From cb3a553583c66730106f40c070b075ad3ac4d381 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 11 Mar 2019 12:30:10 +0100 Subject: [PATCH 59/80] ClangFormat: Indent closing brace on the new line Sometimes the curly brace also requires indentation. These are the cases when it comes directly after the comma, for example inside the initializer list. Lets handle such cases in the similar way we do it for the closing parenthesis. Change-Id: Ia0d25fa08f7224567dd41dd17f9757d9d8b27362 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 23 ++++++++++++++---- tests/unit/unittest/clangformat-test.cpp | 24 +++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index bdf384863ab..e235ea64eb4 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -188,9 +188,11 @@ int forceIndentWithExtraText(QByteArray &buffer, const bool closingParenBlock = firstNonWhitespace >= 0 && blockText.at(firstNonWhitespace) == ')'; + const bool closingBraceBlock = firstNonWhitespace >= 0 + && blockText.at(firstNonWhitespace) == '}'; int extraLength = 0; - if (firstNonWhitespace < 0 || closingParenBlock) { + if (firstNonWhitespace < 0 || closingParenBlock || closingBraceBlock) { if (charContext == CharacterContext::LastAfterComma) { charContext = CharacterContext::AfterComma; } else if (charContext == CharacterContext::Unknown) { @@ -203,12 +205,23 @@ int forceIndentWithExtraText(QByteArray &buffer, } QByteArray dummyText; - if (charContext == CharacterContext::NewStatement) { - dummyText = "a;a;"; - } else if (charContext == CharacterContext::AfterComma) { + switch (charContext) { + case CharacterContext::Unknown: + QTC_ASSERT(false, return 0;); + case CharacterContext::AfterComma: dummyText = "&& a,"; - } else { + break; + case CharacterContext::NewStatement: + if (!closingBraceBlock) + dummyText = "a;a;"; + break; + case CharacterContext::Continuation: + if (closingBraceBlock) + break; + Q_FALLTHROUGH(); + case CharacterContext::LastAfterComma: dummyText = "&& a"; + break; } buffer.insert(utf8Offset, dummyText); diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 56b80d9e223..4052d75db7b 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -417,6 +417,30 @@ TEST_F(ClangFormat, EmptyLineInInitializerList) "};")); } +TEST_F(ClangFormat, IndentClosingBraceAfterComma) +{ + insertLines({"Bar foo{a,", + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("Bar foo{a,", + " }")); +} + +TEST_F(ClangFormat, DoNotIndentClosingBraceAfterSemicolon) +{ + insertLines({"{", + " a;" + "}"}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("{", + " a;" + "}")); +} + TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", From 3017ee23e5502d6ba8dc6b64eb023caf6c278069 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Mon, 11 Mar 2019 14:43:14 +0100 Subject: [PATCH 60/80] ClangFormat: Fix the filepath to actually pick the selected config We've searched for the config we want to use but did not change the path for the source file which is used internally by libformat to find the configuration. Fixes: QTCREATORBUG-22048 Change-Id: Ibdcc33ac338f06e966dfc5c06cdb38db3bb768b6 Reviewed-by: Marco Bubke --- src/plugins/clangformat/clangformatutils.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp index 45ed4feacf1..74c4165a34b 100644 --- a/src/plugins/clangformat/clangformatutils.cpp +++ b/src/plugins/clangformat/clangformatutils.cpp @@ -237,6 +237,12 @@ QString configForFile(Utils::FileName fileName) return configForFile(fileName, true); } +Utils::FileName assumedPathForConfig(const QString &configFile) +{ + Utils::FileName fileName = Utils::FileName::fromString(configFile); + return fileName.parentDir().appendPath("test.cpp"); +} + static clang::format::FormatStyle constructStyle(const QByteArray &baseStyle = QByteArray()) { if (!baseStyle.isEmpty()) { @@ -311,6 +317,7 @@ static clang::format::FormatStyle styleForFile(Utils::FileName fileName, bool ch if (configFile.isEmpty()) return constructStyle(); + fileName = assumedPathForConfig(configFile); Expected style = format::getStyle("file", fileName.toString().toStdString(), "none"); From 5333331362cd329244c4ffba014dfb4949491bf7 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 12 Mar 2019 10:27:19 +0100 Subject: [PATCH 61/80] ClangFormat: Tweak dummy text for consecutive empty lines If empty lines follow each other it makes sense to use the empty comment as dummy text for all but the last one of them. This prevents increasing indentation lengths after if (foo) when there are multiple new empty lines inserted. Change-Id: I4c948161b674b3af0a131bfb85e7a45a80ed3fb0 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 31 ++++++++--- tests/unit/unittest/clangformat-test.cpp | 54 ++++++++++++++++++- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index e235ea64eb4..91f590cdee1 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -154,20 +154,31 @@ CharacterContext characterContext(const QTextBlock ¤tBlock, const QTextBlock &previousNonEmptyBlock) { const QString prevLineText = previousNonEmptyBlock.text().trimmed(); + const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock); if (prevLineText.endsWith(',')) { - const QChar firstNonWhitespaceChar = findFirstNonWhitespaceCharacter(currentBlock); // We don't need to add comma in case it's the last argument. if (firstNonWhitespaceChar == '}' || firstNonWhitespaceChar == ')') return CharacterContext::LastAfterComma; return CharacterContext::AfterComma; } - if (prevLineText.endsWith(';') || prevLineText.endsWith('{') || prevLineText.endsWith('}')) + if (prevLineText.endsWith(';') || prevLineText.endsWith('{') || prevLineText.endsWith('}') + || firstNonWhitespaceChar == QChar::Null) { return CharacterContext::NewStatement; + } return CharacterContext::Continuation; } +bool nextBlockExistsAndEmpty(const QTextBlock ¤tBlock) +{ + QTextBlock nextBlock = currentBlock.next(); + if (!nextBlock.isValid() || nextBlock.position() == currentBlock.position()) + return false; + + return nextBlock.text().trimmed().isEmpty(); +} + // Add extra text in case of the empty line or the line starting with ')'. // Track such extra pieces of text in isInsideModifiedLine(). int forceIndentWithExtraText(QByteArray &buffer, @@ -192,10 +203,15 @@ int forceIndentWithExtraText(QByteArray &buffer, && blockText.at(firstNonWhitespace) == '}'; int extraLength = 0; - if (firstNonWhitespace < 0 || closingParenBlock || closingBraceBlock) { + QByteArray dummyText; + if (firstNonWhitespace < 0 && charContext != CharacterContext::Unknown + && nextBlockExistsAndEmpty(block)) { + // If the next line is also empty it's safer to use a comment line. + dummyText = "//"; + } else if (firstNonWhitespace < 0 || closingParenBlock || closingBraceBlock) { if (charContext == CharacterContext::LastAfterComma) { charContext = CharacterContext::AfterComma; - } else if (charContext == CharacterContext::Unknown) { + } else if (charContext == CharacterContext::Unknown || firstNonWhitespace >= 0) { QTextBlock lastBlock = reverseFindLastEmptyBlock(block); if (lastBlock.position() > 0) lastBlock = lastBlock.previous(); @@ -204,7 +220,6 @@ int forceIndentWithExtraText(QByteArray &buffer, charContext = characterContext(block, lastBlock); } - QByteArray dummyText; switch (charContext) { case CharacterContext::Unknown: QTC_ASSERT(false, return 0;); @@ -223,11 +238,11 @@ int forceIndentWithExtraText(QByteArray &buffer, dummyText = "&& a"; break; } - - buffer.insert(utf8Offset, dummyText); - extraLength += dummyText.length(); } + buffer.insert(utf8Offset, dummyText); + extraLength += dummyText.length(); + if (secondTry) { int nextLinePos = buffer.indexOf('\n', utf8Offset); if (nextLinePos < 0) diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index 4052d75db7b..bb2942b10dd 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -119,14 +119,14 @@ TEST_F(ClangFormat, IndentBasicFile) TEST_F(ClangFormat, IndentEmptyLine) { - insertLines({"int main", + insertLines({"int main()", "{", "", "}"}); indenter.indent(cursor, QChar::Null, TextEditor::TabSettings()); - ASSERT_THAT(documentLines(), ElementsAre("int main", + ASSERT_THAT(documentLines(), ElementsAre("int main()", "{", " ", "}")); @@ -441,6 +441,56 @@ TEST_F(ClangFormat, DoNotIndentClosingBraceAfterSemicolon) "}")); } +TEST_F(ClangFormat, SameIndentAfterSecondNewLineAfterIf) +{ + insertLines({"if (a)", + " ", + ""}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (a)", + " ", + " ")); +} + +TEST_F(ClangFormat, IndentAfterNewLineInsideIfWithFunctionCall) +{ + insertLines({"if (foo()", + ")"}); + + indenter.indentBlock(doc.findBlockByNumber(1), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (foo()", + " )")); +} + +TEST_F(ClangFormat, SameIndentAfterSecondNewLineInsideIfWithFunctionCall) +{ + insertLines({"if (foo()", + " ", + ")"}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (foo()", + " ", + " )")); +} + +TEST_F(ClangFormat, SameIndentsOnNewLinesAfterComments) +{ + insertLines({"namespace {} //comment", + "", + ""}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("namespace {} //comment", + "", + "")); +} + TEST_F(ClangFormat, IndentFunctionBodyButNotFormatBeforeIt) { insertLines({"int foo(int a, int b,", From d7eeb0bd90b5e183a7235a6868a74a3bce7cc30a Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 12 Mar 2019 10:49:49 +0100 Subject: [PATCH 62/80] ClangFormat: Reduce dummy text to minimum size ... and tweak continuation dummy text to fix the indentation for the line with existing text inside parenthesis. Change-Id: Iaebd2f58823fcbeed24bb7e47769af53261c18ca Reviewed-by: Marco Bubke --- src/plugins/clangformat/clangformatbaseindenter.cpp | 6 +++--- tests/unit/unittest/clangformat-test.cpp | 13 +++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 91f590cdee1..7c035792c0b 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -224,18 +224,18 @@ int forceIndentWithExtraText(QByteArray &buffer, case CharacterContext::Unknown: QTC_ASSERT(false, return 0;); case CharacterContext::AfterComma: - dummyText = "&& a,"; + dummyText = "a,"; break; case CharacterContext::NewStatement: if (!closingBraceBlock) - dummyText = "a;a;"; + dummyText = "a;"; break; case CharacterContext::Continuation: if (closingBraceBlock) break; Q_FALLTHROUGH(); case CharacterContext::LastAfterComma: - dummyText = "&& a"; + dummyText = "& a &"; break; } } diff --git a/tests/unit/unittest/clangformat-test.cpp b/tests/unit/unittest/clangformat-test.cpp index bb2942b10dd..ad2c8bf3e36 100644 --- a/tests/unit/unittest/clangformat-test.cpp +++ b/tests/unit/unittest/clangformat-test.cpp @@ -478,6 +478,19 @@ TEST_F(ClangFormat, SameIndentAfterSecondNewLineInsideIfWithFunctionCall) " )")); } +TEST_F(ClangFormat, SameIndentAfterSecondNonEmptyNewLineInsideIfWithFunctionCall) +{ + insertLines({"if (foo()", + " ", + "bar)"}); + + indenter.indentBlock(doc.findBlockByNumber(2), QChar::Null, TextEditor::TabSettings()); + + ASSERT_THAT(documentLines(), ElementsAre("if (foo()", + " ", + " bar)")); +} + TEST_F(ClangFormat, SameIndentsOnNewLinesAfterComments) { insertLines({"namespace {} //comment", From 1e28a66bb52c0920aa790f9f21ff4bb425ee1e1a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 12 Mar 2019 11:24:32 +0100 Subject: [PATCH 63/80] Fix selection color in locator popup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On macOS and Windows the background of the selected item in locator would be light gray, since the popup doesn't really get focus there. We still want it to look the same as if it had focus, so change the palette accordingly. Fixes: QTCREATORBUG-22118 Change-Id: Iefbbd49b4980a01de494e33ddb8e43e2d5a15716 Reviewed-by: AndrĂ© Hartmann --- src/plugins/coreplugin/locator/locatorwidget.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 2421bd776ab..994c9e5d0e8 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -252,6 +252,14 @@ void LocatorModel::addEntries(const QList &entries) CompletionList::CompletionList(QWidget *parent) : Utils::TreeView(parent) { + // on macOS and Windows the popup doesn't really get focus, so fake the selection color + // which would then just be a very light gray, but should look as if it had focus + QPalette p = palette(); + p.setBrush(QPalette::Inactive, + QPalette::Highlight, + p.brush(QPalette::Normal, QPalette::Highlight)); + setPalette(p); + setItemDelegate(new CompletionDelegate(this)); setRootIsDecorated(false); setUniformRowHeights(true); From 7f0589ef591f6ff08a86ec6bca02248dc40443ef Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 12 Mar 2019 11:55:43 +0100 Subject: [PATCH 64/80] ClangFormat: Extract switch statement into function Clarifies the logic and improves readability. Change-Id: I42668c65d73fb455996fa3a9bc5384f0b204a778 Reviewed-by: Marco Bubke --- .../clangformat/clangformatbaseindenter.cpp | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/plugins/clangformat/clangformatbaseindenter.cpp b/src/plugins/clangformat/clangformatbaseindenter.cpp index 7c035792c0b..dcb5edaeb13 100644 --- a/src/plugins/clangformat/clangformatbaseindenter.cpp +++ b/src/plugins/clangformat/clangformatbaseindenter.cpp @@ -29,11 +29,11 @@ #include #include -#include #include +#include -#include #include +#include namespace ClangFormat { @@ -179,6 +179,27 @@ bool nextBlockExistsAndEmpty(const QTextBlock ¤tBlock) return nextBlock.text().trimmed().isEmpty(); } +QByteArray dummyTextForContext(CharacterContext context, bool closingBraceBlock) +{ + if (closingBraceBlock + && (context == CharacterContext::NewStatement + || context == CharacterContext::Continuation)) { + return QByteArray(); + } + + switch (context) { + case CharacterContext::Unknown: + QTC_ASSERT(false, return "";); + case CharacterContext::AfterComma: + return "a,"; + case CharacterContext::NewStatement: + return "a;"; + case CharacterContext::Continuation: + case CharacterContext::LastAfterComma: + return "& a &"; + } +} + // Add extra text in case of the empty line or the line starting with ')'. // Track such extra pieces of text in isInsideModifiedLine(). int forceIndentWithExtraText(QByteArray &buffer, @@ -220,24 +241,7 @@ int forceIndentWithExtraText(QByteArray &buffer, charContext = characterContext(block, lastBlock); } - switch (charContext) { - case CharacterContext::Unknown: - QTC_ASSERT(false, return 0;); - case CharacterContext::AfterComma: - dummyText = "a,"; - break; - case CharacterContext::NewStatement: - if (!closingBraceBlock) - dummyText = "a;"; - break; - case CharacterContext::Continuation: - if (closingBraceBlock) - break; - Q_FALLTHROUGH(); - case CharacterContext::LastAfterComma: - dummyText = "& a &"; - break; - } + dummyText = dummyTextForContext(charContext, closingBraceBlock); } buffer.insert(utf8Offset, dummyText); From bbbf7272726a89a6637a50660af549452d07c4e6 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 11 Mar 2019 07:33:07 +0100 Subject: [PATCH 65/80] LanguageClient: fix restart check for stdio clients Change-Id: I4acb61b48b7ac18423b2e106f1f9ea9b3f7ccb70 Reviewed-by: Christian Stenger --- src/plugins/languageclient/client.cpp | 5 +++++ src/plugins/languageclient/client.h | 1 + src/plugins/languageclient/languageclientinterface.cpp | 2 +- src/plugins/languageclient/languageclientinterface.h | 2 +- src/plugins/languageclient/languageclientsettings.cpp | 4 +++- 5 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index dde08c6794c..244ca4c63aa 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -775,6 +775,11 @@ const DynamicCapabilities &Client::dynamicCapabilities() const return m_dynamicCapabilities; } +const BaseClientInterface *Client::clientInterface() const +{ + return m_clientInterface.data(); +} + void Client::log(const ShowMessageParams &message, Core::MessageManager::PrintToOutputPaneFlag flag) { diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index 2d92424f42d..635512fa287 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -147,6 +147,7 @@ public: const LanguageServerProtocol::ServerCapabilities &capabilities() const; const DynamicCapabilities &dynamicCapabilities() const; + const BaseClientInterface *clientInterface() const; signals: void initialized(LanguageServerProtocol::ServerCapabilities capabilities); diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index b67db95dde1..05980617207 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -110,7 +110,7 @@ StdIOClientInterface::~StdIOClientInterface() Utils::SynchronousProcess::stopProcess(m_process); } -bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) +bool StdIOClientInterface::needsRestart(const StdIOSettings *settings) const { return m_executable != settings->m_executable || m_arguments != settings->m_arguments; } diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index 3dc2602d524..182965ab882 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -74,7 +74,7 @@ public: StdIOClientInterface &operator=(const StdIOClientInterface &) = delete; StdIOClientInterface &operator=(StdIOClientInterface &&) = delete; - bool needsRestart(const StdIOSettings *settings); + bool needsRestart(const StdIOSettings *settings) const; bool start() override; diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index 17ea39f80ed..74ca22d5f2e 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -473,7 +473,9 @@ bool StdIOSettings::needsRestart() const { if (BaseSettings::needsRestart()) return true; - if (auto stdIOInterface = qobject_cast(m_client)) + if (m_client.isNull()) + return false; + if (auto stdIOInterface = qobject_cast(m_client->clientInterface())) return stdIOInterface->needsRestart(this); return false; } From fc5cf08ed8c8da8f1f7c3ee497ee4dc68673bcd0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 12 Mar 2019 12:09:43 +0100 Subject: [PATCH 66/80] Fix regression in timeline Empty keyframe groups were created randomly. Change-Id: I223ac7fe5f0112bafebbab26f05f9a45d59849eb Reviewed-by: Tim Jenssen Reviewed-by: Eike Ziller --- src/plugins/qmldesigner/designercore/include/qmltimeline.h | 2 +- src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/include/qmltimeline.h b/src/plugins/qmldesigner/designercore/include/qmltimeline.h index a92a2921198..c04fd454c0c 100644 --- a/src/plugins/qmldesigner/designercore/include/qmltimeline.h +++ b/src/plugins/qmldesigner/designercore/include/qmltimeline.h @@ -71,10 +71,10 @@ public: void toogleRecording(bool b) const; void resetGroupRecording() const; + bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const; private: void addKeyframeGroupIfNotExists(const ModelNode &node, const PropertyName &propertyName); - bool hasKeyframeGroup(const ModelNode &node, const PropertyName &propertyName) const; QList allKeyframeGroups() const; }; diff --git a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp index 745fdc4d00b..65ed482bfb1 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlobjectnode.cpp @@ -63,7 +63,7 @@ void QmlObjectNode::setVariantProperty(const PropertyName &name, const QVariant timelineFrames.setValue(value, frame); return; - } else if (modelNode().hasId() && timelineIsActive()) { + } else if (modelNode().hasId() && timelineIsActive() && currentTimeline().hasKeyframeGroup(modelNode(), name)) { QmlTimelineKeyframeGroup timelineFrames(currentTimeline().keyframeGroup(modelNode(), name)); Q_ASSERT(timelineFrames.isValid()); From a78bbe48cccf87877ef988cc145e58e64543573b Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 12 Mar 2019 13:04:41 +0100 Subject: [PATCH 67/80] LanguageClient: connect the opened editor to LanguageClientManager ... and not just the first one returned by BaseTextEditor::textEditorForDocument Change-Id: I39e9271b3a2b6c0f131a5ce77959a8d57e462397 Reviewed-by: Eike Ziller --- .../languageclient/languageclientmanager.cpp | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 614617edda4..6fcb7c61533 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -205,20 +205,18 @@ void LanguageClientManager::editorOpened(Core::IEditor *iEditor) for (Client *interface : reachableClients()) interface->openDocument(document); - if (auto textDocument = qobject_cast(document)) { - if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) { - if (TextEditorWidget *widget = editor->editorWidget()) { - connect(widget, &TextEditorWidget::requestLinkAt, this, - [this, filePath = document->filePath()] - (const QTextCursor &cursor, Utils::ProcessLinkCallback &callback){ - findLinkAt(filePath, cursor, callback); - }); - connect(widget, &TextEditorWidget::requestUsages, this, - [this, filePath = document->filePath()] - (const QTextCursor &cursor){ - findUsages(filePath, cursor); - }); - } + if (BaseTextEditor *editor = qobject_cast(iEditor)) { + if (TextEditorWidget *widget = editor->editorWidget()) { + connect(widget, &TextEditorWidget::requestLinkAt, this, + [this, filePath = document->filePath()] + (const QTextCursor &cursor, Utils::ProcessLinkCallback &callback) { + findLinkAt(filePath, cursor, callback); + }); + connect(widget, &TextEditorWidget::requestUsages, this, + [this, filePath = document->filePath()] + (const QTextCursor &cursor) { + findUsages(filePath, cursor); + }); } } } From 1b0cba38dd6d5e72104354bb77ce4ba8f1f9d681 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 12 Mar 2019 13:55:51 +0100 Subject: [PATCH 68/80] Clang: Fix access specifier for variables Static members have a variable declaration kind so we need to check their access specifiers in order to provide proper information about tokens. Fixes: QTCREATORBUG-22082 Change-Id: If455174bd346398a2df3499fa6cf1ea2b4e26965 Reviewed-by: Marco Bubke --- .../clangbackend/source/fulltokeninfo.cpp | 1 + tests/unit/unittest/data/highlightingmarks.cpp | 9 +++++++++ tests/unit/unittest/tokenprocessor-test.cpp | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/tools/clangbackend/source/fulltokeninfo.cpp b/src/tools/clangbackend/source/fulltokeninfo.cpp index eb57abbbe6a..fd59d25766b 100644 --- a/src/tools/clangbackend/source/fulltokeninfo.cpp +++ b/src/tools/clangbackend/source/fulltokeninfo.cpp @@ -181,6 +181,7 @@ void FullTokenInfo::variableKind(const Cursor &cursor) { TokenInfo::variableKind(cursor); + m_extraInfo.accessSpecifier = cursor.accessSpecifier(); m_extraInfo.storageClass = cursor.storageClass(); } diff --git a/tests/unit/unittest/data/highlightingmarks.cpp b/tests/unit/unittest/data/highlightingmarks.cpp index e1a48903ca3..a703e89a11b 100644 --- a/tests/unit/unittest/data/highlightingmarks.cpp +++ b/tests/unit/unittest/data/highlightingmarks.cpp @@ -686,3 +686,12 @@ class NonConstParameterConstructor NonConstParameterConstructor bar(foo); } }; + +class StaticMembersAccess +{ +protected: + static int protectedValue; + +private: + static int privateValue; +}; diff --git a/tests/unit/unittest/tokenprocessor-test.cpp b/tests/unit/unittest/tokenprocessor-test.cpp index 3383c9a3b93..8d79bc95cbf 100644 --- a/tests/unit/unittest/tokenprocessor-test.cpp +++ b/tests/unit/unittest/tokenprocessor-test.cpp @@ -1704,6 +1704,24 @@ TEST_F(TokenProcessor, LambdaLocalVariableCapture) ASSERT_THAT(infos[4], HasOnlyType(HighlightingType::LocalVariable)); } +TEST_F(TokenProcessor, StaticProtectedMember) +{ + const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(693, 31)); + + ClangBackEnd::TokenInfoContainer container(infos[2]); + + ASSERT_THAT(container.extraInfo.accessSpecifier, ClangBackEnd::AccessSpecifier::Protected); +} + +TEST_F(TokenProcessor, StaticPrivateMember) +{ + const auto infos = translationUnit.fullTokenInfosInRange(sourceRange(696, 29)); + + ClangBackEnd::TokenInfoContainer container(infos[2]); + + ASSERT_THAT(container.extraInfo.accessSpecifier, ClangBackEnd::AccessSpecifier::Private); +} + Data *TokenProcessor::d; void TokenProcessor::SetUpTestCase() From 82d6d20acb04ec970ee609e46e4f7d9543b416f4 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Tue, 12 Mar 2019 14:29:15 +0100 Subject: [PATCH 69/80] Clang: Do not show completions after comma in initializer list Appends 0852f889d1. Do not automatically show global completion when initializer list does not have a type, e.g. auto foo = {{},}; Change-Id: I233fef71c60bb79211000df70bf5b04fa2d9df37 Reviewed-by: Marco Bubke --- src/libs/cplusplus/ExpressionUnderCursor.cpp | 2 +- .../clangcodemodel/clangcompletioncontextanalyzer.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libs/cplusplus/ExpressionUnderCursor.cpp b/src/libs/cplusplus/ExpressionUnderCursor.cpp index e176cbde355..6df396d8cfc 100644 --- a/src/libs/cplusplus/ExpressionUnderCursor.cpp +++ b/src/libs/cplusplus/ExpressionUnderCursor.cpp @@ -264,7 +264,7 @@ int ExpressionUnderCursor::startOfFunctionCall(const QTextCursor &cursor) const break; } else if (tk.is(T_LPAREN) || tk.is(T_LBRACE)) { return scanner.startPosition() + tk.utf16charsBegin(); - } else if (tk.is(T_RPAREN)) { + } else if (tk.is(T_RPAREN) || tk.is(T_RBRACE)) { int matchingBrace = scanner.startOfMatchingBrace(index); if (matchingBrace == index) // If no matching brace found diff --git a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp index ad48a60685b..a2c32a537ad 100644 --- a/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp +++ b/src/plugins/clangcodemodel/clangcompletioncontextanalyzer.cpp @@ -110,6 +110,8 @@ int ClangCompletionContextAnalyzer::startOfFunctionCall(int endOfOperator) const functionNameSelector.setPosition(functionNameStart); functionNameSelector.setPosition(index, QTextCursor::KeepAnchor); const QString functionName = functionNameSelector.selectedText().trimmed(); + if (functionName.isEmpty() && m_completionOperator == T_LBRACE) + return endOfOperator; return functionName.isEmpty() ? -1 : functionNameStart; } @@ -139,7 +141,10 @@ void ClangCompletionContextAnalyzer::handleCommaInFunctionCall() const int start = expressionUnderCursor.startOfFunctionCall(textCursor); m_positionEndOfExpression = start; m_positionForProposal = start + 1; // After '(' of function call - m_completionOperator = T_LPAREN; + if (m_interface->characterAt(start) == '(') + m_completionOperator = T_LPAREN; + else + m_completionOperator = T_LBRACE; } } From 2240010a79bab883d6d4956d4f54e11d2dc32b09 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 11 Mar 2019 08:54:12 +0100 Subject: [PATCH 70/80] Debugger: Rename Debugger Console to QML Debugger Console That's what it is. Change-Id: Ia981a0f1882f20821a77eaccc3f961f3fb22caa9 Task-number: QTCREATORBUG-19870 Reviewed-by: Eike Ziller --- src/plugins/debugger/console/console.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/debugger/console/console.h b/src/plugins/debugger/console/console.h index c46add0a864..4690283a346 100644 --- a/src/plugins/debugger/console/console.h +++ b/src/plugins/debugger/console/console.h @@ -58,7 +58,7 @@ public: QWidget *outputWidget(QWidget *) override; QList toolBarWidgets() const override; - QString displayName() const override { return tr("Debugger Console"); } + QString displayName() const override { return tr("QML Debugger Console"); } int priorityInStatusBar() const override; void clearContents() override; void visibilityChanged(bool visible) override; From ffe6030b3a0103f890030e666fb2efe77d44683d Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 12 Mar 2019 17:06:29 +0100 Subject: [PATCH 71/80] Bump version to 4.9 rc Change-Id: Ic17ad9281013fd061c3f23c423a69108e8193385 Reviewed-by: Eike Ziller --- qbs/modules/qtc/qtc.qbs | 6 +++--- qtcreator.pri | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 9a9d6c4021d..aa12f1ee4ea 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -4,16 +4,16 @@ import qbs.FileInfo import "qtc.js" as HelperFunctions Module { - property string qtcreator_display_version: '4.9.0-beta2' + property string qtcreator_display_version: '4.9.0-rc1' property string ide_version_major: '4' property string ide_version_minor: '8' - property string ide_version_release: '83' + property string ide_version_release: '84' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release property string ide_compat_version_major: '4' property string ide_compat_version_minor: '8' - property string ide_compat_version_release: '83' + property string ide_compat_version_release: '84' property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release diff --git a/qtcreator.pri b/qtcreator.pri index ff69b3c405c..aa05d74bed5 100644 --- a/qtcreator.pri +++ b/qtcreator.pri @@ -1,10 +1,10 @@ !isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included") QTCREATOR_PRI_INCLUDED = 1 -QTCREATOR_VERSION = 4.8.83 -QTCREATOR_COMPAT_VERSION = 4.8.83 +QTCREATOR_VERSION = 4.8.84 +QTCREATOR_COMPAT_VERSION = 4.8.84 VERSION = $$QTCREATOR_VERSION -QTCREATOR_DISPLAY_VERSION = 4.9.0-beta2 +QTCREATOR_DISPLAY_VERSION = 4.9.0-rc1 QTCREATOR_COPYRIGHT_YEAR = 2019 BINARY_ARTIFACTS_BRANCH = master From a1973090da0cb6d6da7decace58c72c9e4ce448a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 12 Mar 2019 17:23:55 +0100 Subject: [PATCH 72/80] Fix lupdate issues Change-Id: I0db9094a8161aa8f854ca4fafa16d8bc79a67868 Reviewed-by: hjk --- src/plugins/android/androiddeployqtstep.cpp | 2 +- src/plugins/perfprofiler/perftracepointdialog.h | 2 ++ .../projectexplorer/devicesupport/desktopdevicefactory.h | 2 ++ .../timelineeditor/timelinepropertyitem.h | 4 ++++ .../qmldesignerextension/timelineeditor/timelinesectionitem.h | 2 ++ .../timelineeditor/timelinesettingsmodel.cpp | 4 ++-- 6 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/plugins/android/androiddeployqtstep.cpp b/src/plugins/android/androiddeployqtstep.cpp index 1a0d508a566..1de24c76e7a 100644 --- a/src/plugins/android/androiddeployqtstep.cpp +++ b/src/plugins/android/androiddeployqtstep.cpp @@ -101,7 +101,7 @@ public: setSummaryText(displayName()); auto uninstallPreviousPackage = new QCheckBox(this); - uninstallPreviousPackage->setText(tr("Uninstall previous package")); + uninstallPreviousPackage->setText(AndroidDeployQtStep::tr("Uninstall previous package")); uninstallPreviousPackage->setChecked(step->uninstallPreviousPackage() > AndroidDeployQtStep::Keep); uninstallPreviousPackage->setEnabled(step->uninstallPreviousPackage() != AndroidDeployQtStep::ForceUnintall); diff --git a/src/plugins/perfprofiler/perftracepointdialog.h b/src/plugins/perfprofiler/perftracepointdialog.h index 83e2199dad7..ca5d4e2ae52 100644 --- a/src/plugins/perfprofiler/perftracepointdialog.h +++ b/src/plugins/perfprofiler/perftracepointdialog.h @@ -41,6 +41,8 @@ namespace Ui { class PerfTracePointDialog; } class PerfTracePointDialog : public QDialog { + Q_OBJECT + public: PerfTracePointDialog(); ~PerfTracePointDialog(); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h b/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h index 1ef030e67f6..e69e2842509 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevicefactory.h @@ -32,6 +32,8 @@ namespace Internal { class DesktopDeviceFactory : public IDeviceFactory { + Q_OBJECT + public: DesktopDeviceFactory(); }; diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h index 5cd241b7a33..2b8c00c59bc 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinepropertyitem.h @@ -44,6 +44,8 @@ class TimelineToolButton; class TimelineKeyframeItem : public TimelineMovableAbstractItem { + Q_DECLARE_TR_FUNCTIONS(TimelineKeyframeItem) + public: explicit TimelineKeyframeItem(TimelinePropertyItem *parent, const ModelNode &frame); ~TimelineKeyframeItem() override; @@ -84,6 +86,8 @@ private: class TimelinePropertyItem : public TimelineItem { + Q_OBJECT + public: enum { Type = TimelineConstants::timelinePropertyItemUserType }; diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h index 3c34ba39299..26db04f7579 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesectionitem.h @@ -40,6 +40,8 @@ class TimelineSectionItem; class TimelineBarItem : public TimelineMovableAbstractItem { + Q_DECLARE_TR_FUNCTIONS(TimelineBarItem) + enum class Location { Undefined, Center, Left, Right }; public: diff --git a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp index bbc4963955a..d9e9fd8a1c0 100644 --- a/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp +++ b/src/plugins/qmldesigner/qmldesignerextension/timelineeditor/timelinesettingsmodel.cpp @@ -103,7 +103,7 @@ QWidget *TimelineEditorDelegate::createEditor(QWidget *parent, switch (index.column()) { case TimelineSettingsModel::TimelineRow: { QTC_ASSERT(comboBox, return widget); - comboBox->addItem(tr("None")); + comboBox->addItem(TimelineSettingsModel::tr("None")); for (const auto &timeline : timelineSettingsModel->timelineView()->getTimelines()) { if (!timeline.modelNode().id().isEmpty()) comboBox->addItem(timeline.modelNode().id()); @@ -111,7 +111,7 @@ QWidget *TimelineEditorDelegate::createEditor(QWidget *parent, } break; case TimelineSettingsModel::AnimationRow: { QTC_ASSERT(comboBox, return widget); - comboBox->addItem(tr("None")); + comboBox->addItem(TimelineSettingsModel::tr("None")); for (const auto &animation : timelineSettingsModel->timelineView()->getAnimations(qmlTimeline)) { if (!animation.id().isEmpty()) From 6b59d711a862092ea808cf6ef810f3e96906f582 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 12 Mar 2019 13:46:31 +0100 Subject: [PATCH 73/80] TextEditor: return all BaseTextEditor for a document Change-Id: Iab483528357fdba1b7107130c19370974c03979c Reviewed-by: Eike Ziller --- src/plugins/languageclient/client.cpp | 13 +------------ .../languageclient/languageclientmanager.cpp | 12 ++++++++++++ src/plugins/languageclient/languageclientutils.cpp | 11 ++++++----- src/plugins/texteditor/texteditor.cpp | 7 ++++--- src/plugins/texteditor/texteditor.h | 2 +- 5 files changed, 24 insertions(+), 21 deletions(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 244ca4c63aa..fc9df47ff76 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -208,17 +208,6 @@ void Client::openDocument(Core::IDocument *document) connect(textDocument, &QObject::destroyed, this, [this, textDocument]{ m_resetAssistProvider.remove(textDocument); }); - if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) { - if (QPointer widget = editor->editorWidget()) { - connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){ - // TODO This would better be a compressing timer - QTimer::singleShot(50, this, [this, widget]() { - if (widget) - cursorPositionChanged(widget); - }); - }); - } - } } m_openedDocument.append(document->filePath()); @@ -344,7 +333,7 @@ void Client::documentContentsChanged(Core::IDocument *document) if (textDocument) { using namespace TextEditor; - if (BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(textDocument)) + for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(textDocument)) if (TextEditorWidget *widget = editor->editorWidget()) widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id())); requestDocumentSymbols(textDocument); diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 6fcb7c61533..637a0efa28e 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -217,6 +217,18 @@ void LanguageClientManager::editorOpened(Core::IEditor *iEditor) (const QTextCursor &cursor) { findUsages(filePath, cursor); }); + connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){ + // TODO This would better be a compressing timer + QTimer::singleShot(50, this, + [this, widget = QPointer(widget)]() { + if (widget) { + for (Client *client : this->reachableClients()) { + if (client->isSupportedDocument(widget->textDocument())) + client->cursorPositionChanged(widget); + } + } + }); + }); } } } diff --git a/src/plugins/languageclient/languageclientutils.cpp b/src/plugins/languageclient/languageclientutils.cpp index f81be2427cc..7a28c5e3a95 100644 --- a/src/plugins/languageclient/languageclientutils.cpp +++ b/src/plugins/languageclient/languageclientutils.cpp @@ -133,12 +133,10 @@ void updateCodeActionRefactoringMarker(Client *client, TextDocument* doc = TextDocument::textDocumentForFileName(uri.toFileName()); if (!doc) return; - BaseTextEditor *editor = BaseTextEditor::textEditorForDocument(doc); - if (!editor) + const QVector editors = BaseTextEditor::textEditorsForDocument(doc); + if (editors.isEmpty()) return; - TextEditorWidget *editorWidget = editor->editorWidget(); - const QList &diagnostics = action.diagnostics().value_or(QList()); RefactorMarkers markers; @@ -181,7 +179,10 @@ void updateCodeActionRefactoringMarker(Client *client, marker.cursor = endOfLineCursor(diagnostic.range().start().toTextCursor(doc->document())); markers << marker; } - editorWidget->setRefactorMarkers(markers + editorWidget->refactorMarkers()); + for (BaseTextEditor *editor : editors) { + if (TextEditorWidget *editorWidget = editor->editorWidget()) + editorWidget->setRefactorMarkers(markers + editorWidget->refactorMarkers()); + } } } // namespace LanguageClient diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 0d92b2d16f1..ca6510266c4 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -8512,13 +8512,14 @@ BaseTextEditor *BaseTextEditor::currentTextEditor() return qobject_cast(EditorManager::currentEditor()); } -BaseTextEditor *BaseTextEditor::textEditorForDocument(TextDocument *textDocument) +QVector BaseTextEditor::textEditorsForDocument(TextDocument *textDocument) { + QVector ret; for (IEditor *editor : Core::DocumentModel::editorsForDocument(textDocument)) { if (auto textEditor = qobject_cast(editor)) - return textEditor; + ret << textEditor; } - return nullptr; + return ret; } TextEditorWidget *BaseTextEditor::editorWidget() const diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h index d792a1b12c7..3d079bf77f3 100644 --- a/src/plugins/texteditor/texteditor.h +++ b/src/plugins/texteditor/texteditor.h @@ -111,7 +111,7 @@ public: virtual void finalizeInitialization() {} static BaseTextEditor *currentTextEditor(); - static BaseTextEditor *textEditorForDocument(TextDocument *textDocument); + static QVector textEditorsForDocument(TextDocument *textDocument); TextEditorWidget *editorWidget() const; TextDocument *textDocument() const; From aa7568e027aa11997bdf8fa5ca2fc988b8429947 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 7 Mar 2019 12:06:21 +0100 Subject: [PATCH 74/80] macOS: Package Qt Creator.app.dSYM with debug archive On macOS the debug info for the application is located parallel to the app bundle itself, not somewhere inside the app bundle. I.e. /some/path/Qt Creator.app /some/path/Qt Creator.app.dSYM So for the debug info we must use the parent of the app as a base directory for packaging. Change-Id: Ibb0e8721bb6a5ce272173a264074eece299d18da Reviewed-by: Tim Jenssen --- qtcreator.pro | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/qtcreator.pro b/qtcreator.pro index 98a897aa2b0..2578649905a 100644 --- a/qtcreator.pro +++ b/qtcreator.pro @@ -109,15 +109,19 @@ linux { macx { APPBUNDLE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app" - BINDIST_SOURCE = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app" + BINDIST_SOURCE.release = "$$OUT_PWD/bin/$${IDE_APP_TARGET}.app" + BINDIST_SOURCE.debug = "$$OUT_PWD/bin" + BINDIST_EXCLUDE_ARG.debug = "--exclude-toplevel" deployqt.commands = $$PWD/scripts/deployqtHelper_mac.sh \"$${APPBUNDLE}\" \"$$[QT_INSTALL_BINS]\" \"$$[QT_INSTALL_TRANSLATIONS]\" \"$$[QT_INSTALL_PLUGINS]\" \"$$[QT_INSTALL_IMPORTS]\" \"$$[QT_INSTALL_QML]\" codesign.commands = codesign --deep -s \"$(SIGNING_IDENTITY)\" $(SIGNING_FLAGS) \"$${APPBUNDLE}\" dmg.commands = python -u \"$$PWD/scripts/makedmg.py\" \"$${BASENAME}.dmg\" \"Qt Creator\" \"$$IDE_SOURCE_TREE\" \"$$OUT_PWD/bin\" #dmg.depends = deployqt QMAKE_EXTRA_TARGETS += codesign dmg } else { - BINDIST_SOURCE = "$(INSTALL_ROOT)$$QTC_PREFIX" - BINDIST_EXCLUDE_ARG = "--exclude-toplevel" + BINDIST_SOURCE.release = "$(INSTALL_ROOT)$$QTC_PREFIX" + BINDIST_EXCLUDE_ARG.release = "--exclude-toplevel" + BINDIST_SOURCE.debug = $${BINDIST_SOURCE.release} + BINDIST_EXCLUDE_ARG.debug = $${BINDIST_EXCLUDE_ARG.release} deployqt.commands = python -u $$PWD/scripts/deployqt.py -i \"$(INSTALL_ROOT)$$QTC_PREFIX/bin/$${IDE_APP_TARGET}\" \"$(QMAKE)\" deployqt.depends = install win32 { @@ -140,9 +144,9 @@ isEmpty(INSTALLER_ARCHIVE_FROM_ENV) { INSTALLER_ARCHIVE_DEBUG = $$INSTALLER_ARCHIVE INSTALLER_ARCHIVE_DEBUG ~= s/(.*)[.]7z/\1-debug.7z -bindist.commands = python -u $$PWD/scripts/createDistPackage.py $$OUT_PWD/$${BASENAME}.7z \"$$BINDIST_SOURCE\" -bindist_installer.commands = python -u $$PWD/scripts/createDistPackage.py $$BINDIST_EXCLUDE_ARG $${INSTALLER_ARCHIVE} \"$$BINDIST_SOURCE\" -bindist_debug.commands = python -u $$PWD/scripts/createDistPackage.py --debug $$BINDIST_EXCLUDE_ARG $${INSTALLER_ARCHIVE_DEBUG} \"$$BINDIST_SOURCE\" +bindist.commands = python -u $$PWD/scripts/createDistPackage.py $$OUT_PWD/$${BASENAME}.7z \"$${BINDIST_SOURCE.release}\" +bindist_installer.commands = python -u $$PWD/scripts/createDistPackage.py $${BINDIST_EXCLUDE_ARG.release} $${INSTALLER_ARCHIVE} \"$${BINDIST_SOURCE.release}\" +bindist_debug.commands = python -u $$PWD/scripts/createDistPackage.py --debug $${BINDIST_EXCLUDE_ARG.debug} $${INSTALLER_ARCHIVE_DEBUG} \"$${BINDIST_SOURCE.debug}\" win32 { deployqt.commands ~= s,/,\\\\,g From 83f54fda0d4f59d979d1b8415c99e4b23a2066f0 Mon Sep 17 00:00:00 2001 From: Robert Loehning Date: Wed, 6 Mar 2019 19:24:37 +0100 Subject: [PATCH 75/80] QmlProfiler: Fix variable name Change-Id: I01e8981c440d7e6fe35793b659f477fb8da85e06 Reviewed-by: Ulf Hermann --- src/plugins/qmlprofiler/qmlprofilertool.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 3ea47f86386..13f87b3889b 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -287,10 +287,10 @@ void QmlProfilerTool::updateRunActions() d->m_startAction->setToolTip(tr("A QML Profiler analysis is still in progress.")); d->m_stopAction->setEnabled(true); } else { - QString whyNot = tr("Start QML Profiler analysis."); + QString tooltip = tr("Start QML Profiler analysis."); bool canRun = ProjectExplorerPlugin::canRunStartupProject (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &whyNot); - d->m_startAction->setToolTip(whyNot); + d->m_startAction->setToolTip(tooltip); d->m_startAction->setEnabled(canRun); d->m_stopAction->setEnabled(false); } From 3115d082d36d58e878965675d9fd8573b5b83cd3 Mon Sep 17 00:00:00 2001 From: Alessandro Portale Date: Wed, 13 Mar 2019 13:23:06 +0100 Subject: [PATCH 76/80] QmlProfiler: Compile fix Change-Id: Ie9d593179c26a24a473de9d537968aabaffc67c5 Reviewed-by: Robert Loehning --- src/plugins/qmlprofiler/qmlprofilertool.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmlprofiler/qmlprofilertool.cpp b/src/plugins/qmlprofiler/qmlprofilertool.cpp index 13f87b3889b..2e48a9882bb 100644 --- a/src/plugins/qmlprofiler/qmlprofilertool.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertool.cpp @@ -289,7 +289,7 @@ void QmlProfilerTool::updateRunActions() } else { QString tooltip = tr("Start QML Profiler analysis."); bool canRun = ProjectExplorerPlugin::canRunStartupProject - (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &whyNot); + (ProjectExplorer::Constants::QML_PROFILER_RUN_MODE, &tooltip); d->m_startAction->setToolTip(tooltip); d->m_startAction->setEnabled(canRun); d->m_stopAction->setEnabled(false); From a0072afd492d9653d035b3217ddda954154b2d24 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 13 Mar 2019 10:22:16 +0100 Subject: [PATCH 77/80] Clang: Improve compilation database generation Do not use CompilerOptionsBuilder anymore because we don't need much tweaking for projectPart data and can do it better specifically for the generator. Fixes: QTCREATORBUG-21936 Change-Id: I00ad872c703598a9a88af29399b428520dd5cb3b Reviewed-by: Marco Bubke --- src/plugins/clangcodemodel/clangutils.cpp | 85 +++++++++++++++---- .../cpptools/compileroptionsbuilder.cpp | 2 +- src/plugins/cpptools/compileroptionsbuilder.h | 1 + 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index 481b0774f8f..c8e74f663f5 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -34,12 +34,13 @@ #include #include #include +#include #include +#include #include #include -#include -#include #include +#include #include #include @@ -300,6 +301,18 @@ QString diagnosticCategoryPrefixRemoved(const QString &text) return text; } +static ::Utils::FileName compilerPath(const CppTools::ProjectPart &projectPart) +{ + ProjectExplorer::Target *target = projectPart.project->activeTarget(); + if (!target) + return ::Utils::FileName(); + + ProjectExplorer::ToolChain *toolchain = ProjectExplorer::ToolChainKitInformation::toolChain( + target->kit(), ProjectExplorer::Constants::CXX_LANGUAGE_ID); + + return toolchain->compilerCommand(); +} + static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart) { ProjectExplorer::Target *target = projectPart.project->activeTarget(); @@ -313,17 +326,60 @@ static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart return buildConfig->buildDirectory(); } -static QJsonObject createFileObject(CompilerOptionsBuilder &optionsBuilder, - const ProjectFile &projFile, - const ::Utils::FileName &buildDir) +static QStringList projectPartArguments(const ProjectPart &projectPart) { - const ProjectFile::Kind kind = ProjectFile::classify(projFile.path); - optionsBuilder.updateFileLanguage(kind); + QStringList args; + args << compilerPath(projectPart).toString(); + args << "-c"; + if (projectPart.toolchainType != ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID) { + args << "--target=" + projectPart.toolChainTargetTriple; + args << (projectPart.toolChainWordWidth == ProjectPart::WordWidth64Bit + ? QLatin1String("-m64") + : QLatin1String("-m32")); + } + args << projectPart.compilerFlags; + for (const ProjectExplorer::HeaderPath &headerPath : projectPart.headerPaths) { + if (headerPath.type == ProjectExplorer::HeaderPathType::User) { + args << "-I" + headerPath.path; + } else if (headerPath.type == ProjectExplorer::HeaderPathType::System) { + args << (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID + ? "-I" + : "-isystem") + + headerPath.path; + } + } + for (const ProjectExplorer::Macro ¯o : projectPart.projectMacros) { + args.append(QString::fromUtf8( + macro.toKeyValue(macro.type == ProjectExplorer::MacroType::Define ? "-D" : "-U"))); + } + return args; +} + +static QJsonObject createFileObject(const ::Utils::FileName &buildDir, + const QStringList &arguments, + const ProjectPart &projectPart, + const ProjectFile &projFile) +{ QJsonObject fileObject; fileObject["file"] = projFile.path; - QJsonArray args = QJsonArray::fromStringList(optionsBuilder.options()); - args.prepend(kind == ProjectFile::CXXSource ? "clang++" : "clang"); + QJsonArray args = QJsonArray::fromStringList(arguments); + + const ProjectFile::Kind kind = ProjectFile::classify(projFile.path); + if (projectPart.toolchainType == ProjectExplorer::Constants::MSVC_TOOLCHAIN_TYPEID + || projectPart.toolchainType == ProjectExplorer::Constants::CLANG_CL_TOOLCHAIN_TYPEID) { + if (ProjectFile::isC(kind)) + args.append("/TC"); + else if (ProjectFile::isCxx(kind)) + args.append("/TP"); + } else { + QStringList langOption + = createLanguageOptionGcc(kind, + projectPart.languageExtensions + & ::Utils::LanguageExtension::ObjectiveC); + for (const QString &langOptionPart : langOption) + args.append(langOptionPart); + } args.append(QDir::toNativeSeparators(projFile.path)); fileObject["arguments"] = args; fileObject["directory"] = buildDir.toString(); @@ -338,17 +394,12 @@ void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo p if (!fileOpened) return; compileCommandsFile.write("["); + for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) { const ::Utils::FileName buildDir = buildDirectory(*projectPart); - - CompilerOptionsBuilder optionsBuilder(*projectPart, - UseSystemHeader::No, - UseTweakedHeaderPaths::No); - optionsBuilder.build(CppTools::ProjectFile::Unclassified, - CppTools::UsePrecompiledHeaders::No); - + const QStringList args = projectPartArguments(*projectPart); for (const ProjectFile &projFile : projectPart->files) { - const QJsonObject json = createFileObject(optionsBuilder, projFile, buildDir); + const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile); if (compileCommandsFile.size() > 1) compileCommandsFile.write(","); compileCommandsFile.write('\n' + QJsonDocument(json).toJson().trimmed()); diff --git a/src/plugins/cpptools/compileroptionsbuilder.cpp b/src/plugins/cpptools/compileroptionsbuilder.cpp index f757f2fe2cc..8dfe0c79773 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.cpp +++ b/src/plugins/cpptools/compileroptionsbuilder.cpp @@ -172,7 +172,7 @@ void CompilerOptionsBuilder::addSyntaxOnly() isClStyle() ? add("/Zs") : add("-fsyntax-only"); } -static QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt) +QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt) { QStringList options; diff --git a/src/plugins/cpptools/compileroptionsbuilder.h b/src/plugins/cpptools/compileroptionsbuilder.h index 03564ab6164..349279710ad 100644 --- a/src/plugins/cpptools/compileroptionsbuilder.h +++ b/src/plugins/cpptools/compileroptionsbuilder.h @@ -40,6 +40,7 @@ enum class UseBuildSystemWarnings : char { Yes, No }; CPPTOOLS_EXPORT QStringList XclangArgs(const QStringList &args); CPPTOOLS_EXPORT QStringList clangArgsForCl(const QStringList &args); +CPPTOOLS_EXPORT QStringList createLanguageOptionGcc(ProjectFile::Kind fileKind, bool objcExt); class CPPTOOLS_EXPORT CompilerOptionsBuilder { From d2154e6c40856ff4f044210a928587f3b06ec344 Mon Sep 17 00:00:00 2001 From: Ivan Donchevskii Date: Wed, 13 Mar 2019 14:31:50 +0100 Subject: [PATCH 78/80] Clang: Save compilation database to the build directory For example CMake puts compile_commands.json into the build directory and it makes sense because it uses some target-specific command line options. Change-Id: I92a5b391f35e3f75bbcf41b8efff448f197895bb Reviewed-by: Marco Bubke Reviewed-by: Alessandro Portale Reviewed-by: Christian Kandeler --- .../clangcodemodel/clangcodemodelplugin.cpp | 9 ++++----- src/plugins/clangcodemodel/clangutils.cpp | 14 +++++++++----- src/plugins/clangcodemodel/clangutils.h | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index 11de94c3951..a4a1591cf47 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -68,13 +68,12 @@ void ClangCodeModelPlugin::generateCompilationDB() { using namespace CppTools; ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); - if (!project) + if (!project || !project->activeTarget()) return; - m_generatorWatcher.setFuture(QtConcurrent::run( - &Utils::generateCompilationDB, - project->projectDirectory(), - CppModelManager::instance()->projectInfo(project))); + m_generatorWatcher.setFuture( + QtConcurrent::run(&Utils::generateCompilationDB, + CppModelManager::instance()->projectInfo(project))); } static bool isDBGenerationEnabled(ProjectExplorer::Project *project) diff --git a/src/plugins/clangcodemodel/clangutils.cpp b/src/plugins/clangcodemodel/clangutils.cpp index c8e74f663f5..599b561011e 100644 --- a/src/plugins/clangcodemodel/clangutils.cpp +++ b/src/plugins/clangcodemodel/clangutils.cpp @@ -313,9 +313,9 @@ static ::Utils::FileName compilerPath(const CppTools::ProjectPart &projectPart) return toolchain->compilerCommand(); } -static ::Utils::FileName buildDirectory(const CppTools::ProjectPart &projectPart) +static ::Utils::FileName buildDirectory(const ProjectExplorer::Project &project) { - ProjectExplorer::Target *target = projectPart.project->activeTarget(); + ProjectExplorer::Target *target = project.activeTarget(); if (!target) return ::Utils::FileName(); @@ -386,17 +386,21 @@ static QJsonObject createFileObject(const ::Utils::FileName &buildDir, return fileObject; } -void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo) +void generateCompilationDB(CppTools::ProjectInfo projectInfo) { - QFile compileCommandsFile(projectDir.toString() + "/compile_commands.json"); + const ::Utils::FileName buildDir = buildDirectory(*projectInfo.project()); + QTC_ASSERT(!buildDir.isEmpty(), return;); + QDir dir(buildDir.toString()); + if (!dir.exists()) + dir.mkpath(dir.path()); + QFile compileCommandsFile(buildDir.toString() + "/compile_commands.json"); const bool fileOpened = compileCommandsFile.open(QIODevice::WriteOnly | QIODevice::Truncate); if (!fileOpened) return; compileCommandsFile.write("["); for (ProjectPart::Ptr projectPart : projectInfo.projectParts()) { - const ::Utils::FileName buildDir = buildDirectory(*projectPart); const QStringList args = projectPartArguments(*projectPart); for (const ProjectFile &projFile : projectPart->files) { const QJsonObject json = createFileObject(buildDir, args, *projectPart, projFile); diff --git a/src/plugins/clangcodemodel/clangutils.h b/src/plugins/clangcodemodel/clangutils.h index 4db869896b0..8ced14f5ad6 100644 --- a/src/plugins/clangcodemodel/clangutils.h +++ b/src/plugins/clangcodemodel/clangutils.h @@ -70,7 +70,7 @@ QString diagnosticCategoryPrefixRemoved(const QString &text); ::Utils::CodeModelIcon::Type iconTypeForToken(const ClangBackEnd::TokenInfoContainer &token); -void generateCompilationDB(::Utils::FileName projectDir, CppTools::ProjectInfo projectInfo); +void generateCompilationDB(CppTools::ProjectInfo projectInfo); class DiagnosticTextInfo { From ec1c77fc8ad562c82d1c288ddff09d2102b5d843 Mon Sep 17 00:00:00 2001 From: hjk Date: Thu, 14 Mar 2019 04:20:51 +0100 Subject: [PATCH 79/80] PerfProfiler: Disable when there is no QtQuick Display depends on libTracing, which depends on QtQuick. Change-Id: I5b334a6d846d53e49c19bd9fd1a6d6d24f750f49 Reviewed-by: Ulf Hermann --- src/plugins/plugins.pro | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 9efcf77bf11..b85252288dd 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -59,7 +59,6 @@ SUBDIRS = \ languageclient \ cppcheck \ compilationdatabaseprojectmanager \ - perfprofiler \ qmlpreview qtHaveModule(serialport) { @@ -69,9 +68,9 @@ qtHaveModule(serialport) { } qtHaveModule(quick) { - SUBDIRS += qmlprofiler + SUBDIRS += qmlprofiler perfprofiler } else { - warning("QmlProfiler plugin has been disabled since the Qt Quick module is not available.") + warning("QmlProfiler and PerfProfiler plugins have been disabled since the Qt Quick module is not available.") } qtHaveModule(help) { From 429eb73ace5909e228a58bf8b067823e2be44212 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 14 Mar 2019 10:04:33 +0100 Subject: [PATCH 80/80] TextEditor: fix highlighting whitespaces with ksyntax highlighter Fixes: QTCREATORBUG-22097 Change-Id: Ia69198635e289fc6eff8d95bf1cdf59bda2e04e1 Reviewed-by: Christian Stenger --- src/plugins/texteditor/highlighter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/texteditor/highlighter.cpp b/src/plugins/texteditor/highlighter.cpp index bbd19d28353..5b60b885ab4 100644 --- a/src/plugins/texteditor/highlighter.cpp +++ b/src/plugins/texteditor/highlighter.cpp @@ -290,6 +290,7 @@ void Highlighter::highlightBlock(const QString &text) if (block.isValid()) TextDocumentLayout::userData(block)->setSyntaxState(state); + formatSpaces(text); } void Highlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format)