From 204a2daac0cea1556cdd4bb9d91e5d7a529c0f33 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 25 Oct 2021 15:09:56 +0200 Subject: [PATCH 01/37] Debugger: show info when installed qt misses debug symbols Pointing the user to the relevant package that has to be installed in order to get the full dumper functionality. Task-number: QTCREATORBUG-26456 Change-Id: I0e80f06e1cadcaa9ad2f8a734ca4dda026fc95db Reviewed-by: hjk --- src/plugins/debugger/cdb/cdbengine.cpp | 64 +++++++++++++++++++++++++- src/plugins/debugger/cdb/cdbengine.h | 1 + 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index e1c8be48c31..d685d550d01 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -57,8 +57,11 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -2243,6 +2246,60 @@ static inline bool checkCommandToken(const QString &tokenPrefix, const QString & return ok; } +// look for Qt Core Debug module to check whether it is sdk provided +// and the pdb files are installed in a path discoverable by the debugger +void CdbEngine::checkQtSdkPdbFiles(const QString &module) +{ + const QRegularExpression qtCoreModuleRegExp("(Qt\\dCored).dll"); + const QRegularExpressionMatch match = qtCoreModuleRegExp.match(module); + if (!match.hasMatch()) + return; + const FilePath modulePath = FilePath::fromUserInput(module).parentDir(); + QtSupport::BaseQtVersion *version = QtSupport::QtVersionManager::version( + [modulePath](const QtSupport::BaseQtVersion *version) { + return version->isAutodetected() && version->binPath() == modulePath; + }); + if (!version) + return; + + const QString qtCoreModuleName = match.captured(1); + // Check the usual location of pdb files to avoid the more expensive part of asking cdb + const FilePath pdbPath = modulePath.pathAppended(qtCoreModuleName + ".pdb"); + if (pdbPath.exists()) + return; + + // If there are no pdb files in the usual location, check whether the user has setup the symbol + // path in order to find the debug symbols. + // But first we need to load the symbols in order to check whether the pdb files can be found + runCommand({"ld " + qtCoreModuleName, BuiltinCommand}); + DebuggerCommand cmd; + cmd.function = "lm m " + qtCoreModuleName; + cmd.callback = [this, qtName = version->displayName()](const DebuggerResponse &response) { + if (response.data.m_data.contains("private pdb symbols")) + return; + + const QString message + = tr("The installed %1 is missing debug information files.\n" + "Locals and Expression might not be able to display all Qt Types in a " + "human readable format.\n\n" + "Please install the \"Qt Debug Information Files\" Package from the " + "Maintenance Tool for this Qt installation to get all relevant " + "symbols for the debugger.") + .arg(qtName); + + CheckableMessageBox::doNotShowAgainInformation( + Core::ICore::dialogParent(), + tr("Missing Qt Debug Information"), + message, + Core::ICore::settings(), + "CdbQtSdkPdbHint"); + + showMessage("Missing Qt Debug Information Files package for " + qtName, LogMisc); + }; + cmd.flags = BuiltinCommand; + runCommand(cmd); +} + void CdbEngine::parseOutputLine(QString line) { // The hooked output callback in the extension suppresses prompts, @@ -2351,8 +2408,11 @@ void CdbEngine::parseOutputLine(QString line) // output(32): ModLoad: 00007ffb 00007ffb C:\Windows\system32\KERNEL32.DLL const QRegularExpression moduleRegExp("[0-9a-fA-F]+(`[0-9a-fA-F]+)? [0-9a-fA-F]+(`[0-9a-fA-F]+)? (.*)"); const QRegularExpressionMatch match = moduleRegExp.match(line); - if (match.hasMatch()) - showStatusMessage(tr("Module loaded: %1").arg(match.captured(3).trimmed()), 3000); + if (match.hasMatch()) { + const QString module = match.captured(3).trimmed(); + showStatusMessage(tr("Module loaded: %1").arg(module), 3000); + checkQtSdkPdbFiles(module); + } } else { showMessage(line, LogMisc); } diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 6d3f9aa54b4..6488605d09c 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -194,6 +194,7 @@ private: int elapsedLogTime(); unsigned parseStackTrace(const GdbMi &data, bool sourceStepInto); void mergeStartParametersSourcePathMap(); + void checkQtSdkPdbFiles(const QString &module); const QString m_tokenPrefix; void handleSetupFailure(const QString &errorMessage); From 1a00bb50d444ded7211a78ffe306482effd04675 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 28 Oct 2021 10:03:28 +0200 Subject: [PATCH 02/37] Android: Fix lupdate issues Change-Id: I08bdc81eabb082a091f27d2dea44369573946c49 Reviewed-by: Leena Miettinen Reviewed-by: Assam Boudjelthia --- src/plugins/android/androiddevice.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/plugins/android/androiddevice.cpp b/src/plugins/android/androiddevice.cpp index 3d4376a98fd..600c285edf8 100644 --- a/src/plugins/android/androiddevice.cpp +++ b/src/plugins/android/androiddevice.cpp @@ -90,7 +90,8 @@ AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device) formLayout->addRow(AndroidDevice::tr("Device type:"), new QLabel(dev->deviceTypeName())); const QString serialNumber = dev->serialNumber(); - const QString printableSerialNumber = serialNumber.isEmpty() ? tr("Unknown") : serialNumber; + const QString printableSerialNumber = serialNumber.isEmpty() ? AndroidDevice::tr("Unknown") + : serialNumber; formLayout->addRow(AndroidDevice::tr("Serial number:"), new QLabel(printableSerialNumber)); const QString abis = dev->supportedAbis().join(", "); @@ -100,8 +101,9 @@ AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device) formLayout->addRow(AndroidDevice::tr("OS version:"), new QLabel(osString)); if (dev->machineType() == IDevice::Hardware) { - const QString authorizedStr = dev->deviceState() == IDevice::DeviceReadyToUse ? tr("Yes") - : tr("No"); + const QString authorizedStr = dev->deviceState() == IDevice::DeviceReadyToUse + ? AndroidDevice::tr("Yes") + : AndroidDevice::tr("No"); formLayout->addRow(AndroidDevice::tr("Authorized:"), new QLabel(authorizedStr)); } @@ -117,7 +119,7 @@ AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device) QString AndroidDeviceWidget::dialogTitle() { - return tr("Android Device Manager"); + return AndroidDevice::tr("Android Device Manager"); } bool AndroidDeviceWidget::criticalDialog(const QString &error, QWidget *parent) @@ -480,7 +482,8 @@ void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device, QWidget *parent) return; const QString name = static_cast(device.data())->avdName(); - const QString question = tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name); + const QString question + = AndroidDevice::tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name); if (!AndroidDeviceWidget::questionDialog(question, parent)) return; @@ -515,9 +518,10 @@ void AndroidDeviceManager::setEmulatorArguments(QWidget *parent) "https://developer.android.com/studio/run/emulator-commandline#startup-options"; QInputDialog dialog(parent ? parent : Core::ICore::dialogParent()); - dialog.setWindowTitle(tr("Emulator Command-line Startup Options")); - dialog.setLabelText(tr("Emulator command-line startup options " - "(Help Web Page):").arg(helpUrl)); + dialog.setWindowTitle(AndroidDevice::tr("Emulator Command-line Startup Options")); + dialog.setLabelText(AndroidDevice::tr("Emulator command-line startup options " + "(Help Web Page):") + .arg(helpUrl)); dialog.setTextValue(m_androidConfig.emulatorArgs().join(' ')); if (auto label = dialog.findChild()) { From d8d4739bc4519637dffd04ac19f72612c1c388da Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 27 Oct 2021 13:46:15 +0200 Subject: [PATCH 03/37] TextEditor: Allow special highlighting for static members Task-number: QTCREATORBUG-9659 Change-Id: Idae529fd876ba5f555c76e4d282efc9263263d6c Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 2 ++ .../clangcodemodel/test/clangdtests.cpp | 4 +-- src/plugins/cppeditor/cppchecksymbols.cpp | 6 +++- src/plugins/cppeditor/semantichighlighter.cpp | 6 ++++ src/plugins/cppeditor/semantichighlighter.h | 3 ++ .../texteditor/texteditorconstants.cpp | 1 + src/plugins/texteditor/texteditorconstants.h | 1 + src/plugins/texteditor/texteditorsettings.cpp | 4 +++ src/plugins/texteditor/textstyles.h | 10 ++++-- .../checksymbols/tst_checksymbols.cpp | 33 ++++++++++--------- 10 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 0c6b16e2bc9..73dfe21a8da 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -2463,6 +2463,8 @@ static void semanticHighlighter(QFutureInterface &future, } if (token.modifiers.contains("declaration")) styles.mixinStyles.push_back(C_DECLARATION); + if (token.modifiers.contains("static")) + styles.mixinStyles.push_back(C_STATIC_MEMBER); if (isOutputParameter(token)) styles.mixinStyles.push_back(C_OUTPUT_ARGUMENT); qCDebug(clangdLogHighlight) << "adding highlighting result" diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp index 82e64fad787..29f3a980eb4 100644 --- a/src/plugins/clangcodemodel/test/clangdtests.cpp +++ b/src/plugins/clangcodemodel/test/clangdtests.cpp @@ -1099,9 +1099,9 @@ void ClangdTestHighlighting::test_data() QTest::newRow("local variable captured by lambda") << 442 << 24 << 442 << 27 << QList{C_LOCAL} << 0; QTest::newRow("static protected member") << 693 << 16 << 693 << 30 - << QList{C_FIELD, C_DECLARATION} << 0; + << QList{C_FIELD, C_DECLARATION, C_STATIC_MEMBER} << 0; QTest::newRow("static private member") << 696 << 16 << 696 << 28 - << QList{C_FIELD, C_DECLARATION} << 0; + << QList{C_FIELD, C_DECLARATION, C_STATIC_MEMBER} << 0; QTest::newRow("alias template declaration (opening angle bracket)") << 700 << 10 << 700 << 11 << QList{C_PUNCTUATION} << int(CppEditor::SemanticHighlighter::AngleBracketOpen); QTest::newRow("alias template declaration (closing angle bracket)") << 700 << 16 << 700 << 17 diff --git a/src/plugins/cppeditor/cppchecksymbols.cpp b/src/plugins/cppeditor/cppchecksymbols.cpp index ab1baf8d38b..68dffa6c805 100644 --- a/src/plugins/cppeditor/cppchecksymbols.cpp +++ b/src/plugins/cppeditor/cppchecksymbols.cpp @@ -1305,7 +1305,8 @@ bool CheckSymbols::maybeAddField(const QList &candidates, NameAST *a getTokenStartPosition(startToken, &line, &column); const unsigned length = tok.utf16chars(); - const Result use(line, column, length, SemanticHighlighter::FieldUse); + const Result use(line, column, length, c->isStatic() + ? SemanticHighlighter::StaticFieldUse : SemanticHighlighter::FieldUse); addUse(use); return true; @@ -1359,12 +1360,15 @@ bool CheckSymbols::maybeAddFunction(const QList &candidates, NameAST continue; // TODO: add diagnostic messages and color call-operators calls too? const bool isVirtual = funTy->isVirtual(); + const bool isStaticMember = funTy->isStatic() && funTy->enclosingClass(); Kind matchingKind; if (functionKind == FunctionDeclaration) { matchingKind = isVirtual ? SemanticHighlighter::VirtualFunctionDeclarationUse + : isStaticMember ? SemanticHighlighter::StaticMethodDeclarationUse : SemanticHighlighter::FunctionDeclarationUse; } else { matchingKind = isVirtual ? SemanticHighlighter::VirtualMethodUse + : isStaticMember ? SemanticHighlighter::StaticMethodUse : SemanticHighlighter::FunctionUse; } if (argumentCount < funTy->minimumArgumentCount()) { diff --git a/src/plugins/cppeditor/semantichighlighter.cpp b/src/plugins/cppeditor/semantichighlighter.cpp index 6a02566981a..7c92044b2f0 100644 --- a/src/plugins/cppeditor/semantichighlighter.cpp +++ b/src/plugins/cppeditor/semantichighlighter.cpp @@ -328,6 +328,12 @@ void SemanticHighlighter::updateFormatMapFromFontSettings() m_formatMap[VirtualFunctionDeclarationUse] = fs.toTextCharFormat(TextStyles::mixinStyle(C_VIRTUAL_METHOD, C_DECLARATION)); m_formatMap[PseudoKeywordUse] = fs.toTextCharFormat(C_KEYWORD); + m_formatMap[StaticFieldUse] + = fs.toTextCharFormat(TextStyles::mixinStyle(C_FIELD, C_STATIC_MEMBER)); + m_formatMap[StaticMethodUse] + = fs.toTextCharFormat(TextStyles::mixinStyle(C_FUNCTION, C_STATIC_MEMBER)); + m_formatMap[StaticMethodDeclarationUse] = fs.toTextCharFormat( + TextStyles::mixinStyle(C_FUNCTION, {C_DECLARATION, C_STATIC_MEMBER})); } } // namespace CppEditor diff --git a/src/plugins/cppeditor/semantichighlighter.h b/src/plugins/cppeditor/semantichighlighter.h index 1acbabcff96..edec88ed7a5 100644 --- a/src/plugins/cppeditor/semantichighlighter.h +++ b/src/plugins/cppeditor/semantichighlighter.h @@ -58,6 +58,9 @@ public: PseudoKeywordUse, FunctionDeclarationUse, VirtualFunctionDeclarationUse, + StaticFieldUse, + StaticMethodUse, + StaticMethodDeclarationUse, AngleBracketOpen, AngleBracketClose, DoubleAngleBracketClose, diff --git a/src/plugins/texteditor/texteditorconstants.cpp b/src/plugins/texteditor/texteditorconstants.cpp index 6063b1c5e8b..b7ed7802873 100644 --- a/src/plugins/texteditor/texteditorconstants.cpp +++ b/src/plugins/texteditor/texteditorconstants.cpp @@ -114,6 +114,7 @@ const char *nameForStyle(TextStyle style) case C_DECLARATION: return "Declaration"; case C_FUNCTION_DEFINITION: return "FunctionDefinition"; case C_OUTPUT_ARGUMENT: return "OutputArgument"; + case C_STATIC_MEMBER: return "StaticMember"; case C_LAST_STYLE_SENTINEL: return "LastStyleSentinel"; } diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h index c3f65a54c9e..a1ae0ec540d 100644 --- a/src/plugins/texteditor/texteditorconstants.h +++ b/src/plugins/texteditor/texteditorconstants.h @@ -114,6 +114,7 @@ enum TextStyle : quint8 { C_DECLARATION, C_FUNCTION_DEFINITION, C_OUTPUT_ARGUMENT, + C_STATIC_MEMBER, C_LAST_STYLE_SENTINEL }; diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index aad1ac7a62e..b2a77953dfb 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -361,6 +361,10 @@ FormatDescriptions TextEditorSettingsPrivate::initialFormats() tr("Writable arguments of a function call."), outputArgumentFormat, FormatDescription::ShowAllControls); + formatDescr.emplace_back(C_STATIC_MEMBER, + tr("Static Member"), + tr("Names of static fields or member functions."), + FormatDescription::ShowAllControls); return formatDescr; } diff --git a/src/plugins/texteditor/textstyles.h b/src/plugins/texteditor/textstyles.h index a2151527e50..bf6d04eb995 100644 --- a/src/plugins/texteditor/textstyles.h +++ b/src/plugins/texteditor/textstyles.h @@ -36,14 +36,20 @@ struct TextStyles { TextStyle mainStyle; MixinTextStyles mixinStyles; - static TextStyles mixinStyle(TextStyle main, TextStyle mixin) + static TextStyles mixinStyle(TextStyle main, const QList &mixins) { TextStyles res; res.mainStyle = main; res.mixinStyles.initializeElements(); - res.mixinStyles.push_back(mixin); + for (TextStyle mixin : mixins) + res.mixinStyles.push_back(mixin); return res; } + + static TextStyles mixinStyle(TextStyle main, TextStyle mixin) + { + return mixinStyle(main, QList{mixin}); + } }; } // namespace TextEditor diff --git a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp index ae1eefa8d55..0f7bd8b136b 100644 --- a/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp +++ b/tests/auto/cplusplus/checksymbols/tst_checksymbols.cpp @@ -72,6 +72,9 @@ static QString useKindToString(UseKind useKind) CASE_STR(FunctionUse); CASE_STR(FunctionDeclarationUse); CASE_STR(PseudoKeywordUse); + CASE_STR(StaticFieldUse); + CASE_STR(StaticMethodUse); + CASE_STR(StaticMethodDeclarationUse); default: QTest::qFail("Unknown UseKind", __FILE__, __LINE__); return QLatin1String("Unknown UseKind"); @@ -361,21 +364,21 @@ void tst_CheckSymbols::test_checksymbols_data() "}\n") << (UseList() << Use(1, 8, 5, Highlighting::TypeUse) - << Use(3, 16, 3, Highlighting::FieldUse) + << Use(3, 16, 3, Highlighting::StaticFieldUse) << Use(4, 12, 5, Highlighting::TypeUse) << Use(6, 9, 5, Highlighting::TypeUse) << Use(6, 16, 5, Highlighting::FieldUse) << Use(7, 14, 3, Highlighting::FunctionDeclarationUse) << Use(11, 5, 5, Highlighting::TypeUse) - << Use(11, 12, 3, Highlighting::FieldUse) + << Use(11, 12, 3, Highlighting::FieldUse) // FIXME: Should be StaticField << Use(13, 6, 5, Highlighting::TypeUse) << Use(13, 13, 5, Highlighting::TypeUse) << Use(13, 20, 3, Highlighting::FunctionDeclarationUse) - << Use(15, 5, 3, Highlighting::FieldUse) + << Use(15, 5, 3, Highlighting::StaticFieldUse) << Use(16, 5, 5, Highlighting::TypeUse) - << Use(16, 12, 3, Highlighting::FieldUse) + << Use(16, 12, 3, Highlighting::FieldUse) // FIXME: Should be StaticField << Use(17, 5, 5, Highlighting::FieldUse) - << Use(17, 12, 3, Highlighting::FieldUse)); + << Use(17, 12, 3, Highlighting::StaticFieldUse)); QTest::newRow("VariableHasTheSameNameAsEnumUse") << _("struct Foo\n" @@ -443,11 +446,11 @@ void tst_CheckSymbols::test_checksymbols_data() "}\n") << (UseList() << Use(1, 8, 3, Highlighting::TypeUse) - << Use(3, 16, 3, Highlighting::FunctionDeclarationUse) + << Use(3, 16, 3, Highlighting::StaticMethodDeclarationUse) << Use(6, 6, 3, Highlighting::FunctionDeclarationUse) << Use(8, 9, 3, Highlighting::LocalUse) << Use(8, 15, 3, Highlighting::TypeUse) - << Use(8, 20, 3, Highlighting::FunctionUse)); + << Use(8, 20, 3, Highlighting::StaticMethodUse)); QTest::newRow("8902_staticFunctionHighlightingAsMember_functionArgument") << _("struct Foo\n" @@ -461,11 +464,11 @@ void tst_CheckSymbols::test_checksymbols_data() "}\n") << (UseList() << Use(1, 8, 3, Highlighting::TypeUse) - << Use(3, 16, 3, Highlighting::FunctionDeclarationUse) + << Use(3, 16, 3, Highlighting::StaticMethodDeclarationUse) << Use(6, 6, 3, Highlighting::FunctionDeclarationUse) << Use(6, 14, 3, Highlighting::LocalUse) << Use(8, 5, 3, Highlighting::TypeUse) - << Use(8, 10, 3, Highlighting::FunctionUse)); + << Use(8, 10, 3, Highlighting::StaticMethodUse)); QTest::newRow("8902_staticFunctionHighlightingAsMember_templateParameter") << _("struct Foo\n" @@ -480,11 +483,11 @@ void tst_CheckSymbols::test_checksymbols_data() "}\n") << (UseList() << Use(1, 8, 3, Highlighting::TypeUse) - << Use(3, 16, 3, Highlighting::FunctionDeclarationUse) + << Use(3, 16, 3, Highlighting::StaticMethodDeclarationUse) << Use(6, 17, 3, Highlighting::TypeUse) << Use(7, 6, 3, Highlighting::FunctionDeclarationUse) << Use(9, 5, 3, Highlighting::TypeUse) - << Use(9, 10, 3, Highlighting::FunctionUse)); + << Use(9, 10, 3, Highlighting::StaticMethodUse)); QTest::newRow("staticFunctionHighlightingAsMember_struct") << _("struct Foo\n" @@ -499,11 +502,11 @@ void tst_CheckSymbols::test_checksymbols_data() "}\n") << (UseList() << Use(1, 8, 3, Highlighting::TypeUse) - << Use(3, 16, 3, Highlighting::FunctionDeclarationUse) + << Use(3, 16, 3, Highlighting::StaticMethodDeclarationUse) << Use(6, 8, 3, Highlighting::TypeUse) << Use(7, 6, 3, Highlighting::FunctionDeclarationUse) << Use(9, 5, 3, Highlighting::TypeUse) - << Use(9, 10, 3, Highlighting::FunctionUse)); + << Use(9, 10, 3, Highlighting::StaticMethodUse)); QTest::newRow("QTCREATORBUG8890_danglingPointer") << _("template class QList {\n" @@ -569,13 +572,13 @@ void tst_CheckSymbols::test_checksymbols_data() << Use(1, 17, 1, Highlighting::TypeUse) << Use(2, 7, 9, Highlighting::TypeUse) << Use(5, 12, 1, Highlighting::TypeUse) - << Use(5, 15, 8, Highlighting::FunctionDeclarationUse) + << Use(5, 15, 8, Highlighting::StaticMethodDeclarationUse) << Use(8, 6, 3, Highlighting::FunctionDeclarationUse) << Use(10, 6, 3, Highlighting::FunctionDeclarationUse); for (int i = 0; i < 250; ++i) { excessiveUses << Use(12 + i, 5, 9, Highlighting::TypeUse) - << Use(12 + i, 28, 8, Highlighting::FunctionUse); + << Use(12 + i, 28, 8, Highlighting::StaticMethodUse); } QTest::newRow("QTCREATORBUG8974_danglingPointer") << excessive From a437539096e8d5e4a49101f5d05774667089dc0d Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 27 Oct 2021 17:11:28 +0200 Subject: [PATCH 04/37] CppEditor: Fix doxygen comment magic before templates Fixes: QTCREATORBUG-9620 Change-Id: I65a434d72adbe72d449783a917444c2ee216fc5e Reviewed-by: Christian Stenger --- src/plugins/cppeditor/cppdoxygen_test.cpp | 14 ++++++++++++++ src/plugins/cppeditor/doxygengenerator.cpp | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/plugins/cppeditor/cppdoxygen_test.cpp b/src/plugins/cppeditor/cppdoxygen_test.cpp index c9c40a8dd80..7e2781a6ce4 100644 --- a/src/plugins/cppeditor/cppdoxygen_test.cpp +++ b/src/plugins/cppeditor/cppdoxygen_test.cpp @@ -326,6 +326,20 @@ void DoxygenTest::testBasic_data() "};\n" ); + QTest::newRow("classTemplate") << _( + "bool preventFolding;\n" + "/**|\n" + "template class C {\n" + "};\n" + ) << _( + "bool preventFolding;\n" + "/**\n" + " * @brief The C class\n" + " */\n" + "template class C {\n" + "};\n" + ); + QTest::newRow("continuation_after_text_in_first_line") << _( "bool preventFolding;\n" "/*! leading comment|\n" diff --git a/src/plugins/cppeditor/doxygengenerator.cpp b/src/plugins/cppeditor/doxygengenerator.cpp index aba3655b811..9ab9e109eb6 100644 --- a/src/plugins/cppeditor/doxygengenerator.cpp +++ b/src/plugins/cppeditor/doxygengenerator.cpp @@ -141,6 +141,9 @@ QString DoxygenGenerator::generate(QTextCursor cursor, QString DoxygenGenerator::generate(QTextCursor cursor, DeclarationAST *decl) { + if (const TemplateDeclarationAST * const templDecl = decl->asTemplateDeclaration()) + decl = templDecl->declaration; + SpecifierAST *spec = nullptr; DeclaratorAST *decltr = nullptr; if (SimpleDeclarationAST *simpleDecl = decl->asSimpleDeclaration()) { From 399a5cb71351f1e703dd38f134514a344752c544 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 28 Oct 2021 10:31:57 +0200 Subject: [PATCH 05/37] Debugger: make inappropriate debugger warning silenceable Task-number: QTCREATORBUG-14539 Change-Id: Idb119736816c933509fac5748beb547696a991c0 Reviewed-by: hjk Reviewed-by: David Schulz --- src/plugins/debugger/debuggerengine.cpp | 69 +++++++++++++++---------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index f2441aff33a..6d2f628cd34 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -74,6 +74,7 @@ #include #include +#include #include #include #include @@ -2729,27 +2730,34 @@ Context CppDebuggerEngine::languageContext() const void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) { + static const QString warnOnInappropriateDebuggerKey = "DebuggerWarnOnInappropriateDebugger"; + QtcSettings *coreSettings = Core::ICore::settings(); + const bool warnOnRelease = debuggerSettings()->warnOnReleaseBuilds.value() && rp.toolChainAbi.osFlavor() != Abi::AndroidLinuxFlavor; bool warnOnInappropriateDebugger = false; QString detailedWarning; switch (rp.toolChainAbi.binaryFormat()) { case Abi::PEFormat: { - QString preferredDebugger; - if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) { - if (rp.cppEngineType == CdbEngineType) - preferredDebugger = "GDB"; - } else if (rp.cppEngineType != CdbEngineType) { - // osFlavor() is MSVC, so the recommended debugger is CDB - preferredDebugger = "CDB"; - } - if (!preferredDebugger.isEmpty()) { - warnOnInappropriateDebugger = true; - detailedWarning = DebuggerEngine::tr( - "The inferior is in the Portable Executable format.\n" - "Selecting %1 as debugger would improve the debugging " - "experience for this binary format.").arg(preferredDebugger); - break; + if (CheckableMessageBox::shouldAskAgain(coreSettings, warnOnInappropriateDebuggerKey)) { + QString preferredDebugger; + if (rp.toolChainAbi.osFlavor() == Abi::WindowsMSysFlavor) { + if (rp.cppEngineType == CdbEngineType) + preferredDebugger = "GDB"; + } else if (rp.cppEngineType != CdbEngineType && rp.cppEngineType != LldbEngineType) { + // osFlavor() is MSVC, so the recommended debugger is still CDB, + // but don't warn for LLDB which starts to be usable, too. + preferredDebugger = "CDB"; + } + if (!preferredDebugger.isEmpty()) { + warnOnInappropriateDebugger = true; + detailedWarning = DebuggerEngine::tr( + "The inferior is in the Portable Executable format.\n" + "Selecting %1 as debugger would improve the debugging " + "experience for this binary format.") + .arg(preferredDebugger); + break; + } } if (warnOnRelease && rp.cppEngineType == CdbEngineType @@ -2771,13 +2779,15 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) break; } case Abi::ElfFormat: { - if (rp.cppEngineType == CdbEngineType) { - warnOnInappropriateDebugger = true; - detailedWarning = DebuggerEngine::tr( - "The inferior is in the ELF format.\n" - "Selecting GDB or LLDB as debugger would improve the debugging " - "experience for this binary format."); - break; + if (CheckableMessageBox::shouldAskAgain(coreSettings, warnOnInappropriateDebuggerKey)) { + if (rp.cppEngineType == CdbEngineType) { + warnOnInappropriateDebugger = true; + detailedWarning = DebuggerEngine::tr( + "The inferior is in the ELF format.\n" + "Selecting GDB or LLDB as debugger would improve the debugging " + "experience for this binary format."); + break; + } } ElfReader reader(rp.symbolFile); @@ -2876,11 +2886,16 @@ void CppDebuggerEngine::validateRunParameters(DebuggerRunParameters &rp) return; } if (warnOnInappropriateDebugger) { - AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"), - DebuggerEngine::tr("The selected debugger may be inappropriate for the inferior.\n" - "Examining symbols and setting breakpoints by file name and line number " - "may fail.\n") - + '\n' + detailedWarning); + CheckableMessageBox::doNotShowAgainInformation( + Core::ICore::dialogParent(), + DebuggerEngine::tr("Warning"), + DebuggerEngine::tr( + "The selected debugger may be inappropriate for the inferior.\n" + "Examining symbols and setting breakpoints by file name and line number " + "may fail.\n") + + '\n' + detailedWarning, + Core::ICore::settings(), + warnOnInappropriateDebuggerKey); } else if (warnOnRelease) { AsynchronousMessageBox::information(DebuggerEngine::tr("Warning"), DebuggerEngine::tr("This does not seem to be a \"Debug\" build.\n" From ab86842ac5ce6363aec5b4dbe7d5e0ce85ab745a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 28 Oct 2021 13:10:52 +0200 Subject: [PATCH 06/37] Bump version to 6.0-rc1 Change-Id: I08fc4a48ad6089e4477230824317ae0f1bd408e5 Reviewed-by: Eike Ziller --- cmake/QtCreatorIDEBranding.cmake | 6 +++--- qbs/modules/qtc/qtc.qbs | 6 +++--- qtcreator_ide_branding.pri | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 1a89b8888f9..cced80b3e20 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ -set(IDE_VERSION "5.83.0") # The IDE version. -set(IDE_VERSION_COMPAT "5.83.0") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "6.0.0-beta2") # The IDE display version. +set(IDE_VERSION "5.84.0") # The IDE version. +set(IDE_VERSION_COMPAT "5.84.0") # The IDE Compatibility version. +set(IDE_VERSION_DISPLAY "6.0.0-rc1") # The IDE display version. set(IDE_COPYRIGHT_YEAR "2021") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index e6e984ad719..ea2dedef4bf 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -3,15 +3,15 @@ import qbs.Environment import qbs.FileInfo Module { - property string qtcreator_display_version: '6.0.0-beta2' + property string qtcreator_display_version: '6.0.0-rc1' property string ide_version_major: '5' - property string ide_version_minor: '83' + property string ide_version_minor: '84' property string ide_version_release: '0' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release property string ide_compat_version_major: '5' - property string ide_compat_version_minor: '83' + property string ide_compat_version_minor: '84' property string ide_compat_version_release: '0' property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release diff --git a/qtcreator_ide_branding.pri b/qtcreator_ide_branding.pri index 79f08928717..a47d5c24928 100644 --- a/qtcreator_ide_branding.pri +++ b/qtcreator_ide_branding.pri @@ -1,6 +1,6 @@ -QTCREATOR_VERSION = 5.83.0 -QTCREATOR_COMPAT_VERSION = 5.83.0 -QTCREATOR_DISPLAY_VERSION = 6.0.0-beta2 +QTCREATOR_VERSION = 5.84.0 +QTCREATOR_COMPAT_VERSION = 5.84.0 +QTCREATOR_DISPLAY_VERSION = 6.0.0-rc1 QTCREATOR_COPYRIGHT_YEAR = 2021 IDE_DISPLAY_NAME = Qt Creator From 1f7ada80660ec22abf0f076250e7fcdad8c671b8 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 21 Oct 2021 13:23:07 +0300 Subject: [PATCH 07/37] QmlDesigner: Remove default properties removed from model also from QML If default property has actual value, binding, or inline node set, it should be removed also from the QML doc when removed from the model. Fixes: QDS-5239 Change-Id: Iffc27685321f96af46148ab877566c2026cc47d5 Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Bot --- .../designercore/model/modeltotextmerger.cpp | 7 +++++- .../designercore/model/rewriterview.cpp | 23 +++++++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp index b2f36b54565..5a4276a416f 100644 --- a/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/modeltotextmerger.cpp @@ -74,8 +74,13 @@ void ModelToTextMerger::nodeRemoved(const ModelNode &removedNode, const NodeAbst void ModelToTextMerger::propertiesRemoved(const QList& propertyList) { foreach (const AbstractProperty &property, propertyList) { - if (isInHierarchy(property) && !property.isDefaultProperty()) + // Default property that has actual binding/value should be removed + if (isInHierarchy(property) && (!property.isDefaultProperty() + || property.isBindingProperty() + || property.isVariantProperty() + || property.isNodeProperty())) { schedule(new RemovePropertyRewriteAction(property)); + } } } diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index e33c82b1245..84b3678f5d5 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -173,14 +173,27 @@ void RewriterView::propertiesAboutToBeRemoved(const QList &pro if (textToModelMerger()->isActive()) return; + for (const AbstractProperty &property : propertyList) { + if (!property.isDefaultProperty()) + continue; - foreach (const AbstractProperty &property, propertyList) { - if (property.isDefaultProperty() && property.isNodeListProperty()) { - m_removeDefaultPropertyTransaction = beginRewriterTransaction(QByteArrayLiteral("RewriterView::propertiesAboutToBeRemoved")); + if (!m_removeDefaultPropertyTransaction.isValid()) { + m_removeDefaultPropertyTransaction = beginRewriterTransaction( + QByteArrayLiteral("RewriterView::propertiesAboutToBeRemoved")); + } - foreach (const ModelNode &node, property.toNodeListProperty().toModelNodeList()) { - modelToTextMerger()->nodeRemoved(node, property.toNodeAbstractProperty(), AbstractView::NoAdditionalChanges); + if (property.isNodeListProperty()) { + const auto nodeList = property.toNodeListProperty().toModelNodeList(); + for (const ModelNode &node : nodeList) { + modelToTextMerger()->nodeRemoved(node, property.toNodeAbstractProperty(), + AbstractView::NoAdditionalChanges); } + } else if (property.isBindingProperty() || property.isVariantProperty() + || property.isNodeProperty()) { + // Default property that has actual binding/value should be removed. + // We need to do it here in propertiesAboutToBeRemoved, because + // type is no longer determinable after property is removed from the model. + modelToTextMerger()->propertiesRemoved({property}); } } } From 5d3bc6a0c3cd21db94fc8bfd9856bcdf8292f634 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 26 Oct 2021 18:07:45 +0300 Subject: [PATCH 08/37] QmlDesigner: Execute assets adding in 1 transaction When dropping external assets, create the items in 1 transaction so that 1 undo press undos all assets creation. Change-Id: I45b38542f41964a18fd6095eea9bf61b9dca4392 Reviewed-by: Qt CI Bot Reviewed-by: Miikka Heikkinen Reviewed-by: Thomas Hartmann --- .../components/edit3d/edit3dwidget.cpp | 26 +++++++++------- .../formeditor/formeditorwidget.cpp | 30 +++++++++++-------- .../designercore/include/qmlvisualnode.h | 5 ++-- .../designercore/model/qmlitemnode.cpp | 2 +- .../designercore/model/qmlvisualnode.cpp | 5 ++-- 5 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 835ba07b5b2..968cab58466 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -177,18 +177,22 @@ void Edit3DWidget::dropEvent(QDropEvent *dropEvent) ->viewManager().designerActionManager(); QHash addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); - // add 3D assets to 3d editor (QtQuick3D import will be added if missing) - ItemLibraryInfo *itemLibInfo = m_view->model()->metaInfo().itemLibraryInfo(); + view()->executeInTransaction("Edit3DWidget::dropEvent", [&] { + // add 3D assets to 3d editor (QtQuick3D import will be added if missing) + ItemLibraryInfo *itemLibInfo = m_view->model()->metaInfo().itemLibraryInfo(); - const QStringList added3DAssets = addedAssets.value(ComponentCoreConstants::add3DAssetsDisplayString); - for (const QString &assetPath : added3DAssets) { - QString fileName = QFileInfo(assetPath).baseName(); - fileName = fileName.at(0).toUpper() + fileName.mid(1); // capitalize first letter - QString type = QString("Quick3DAssets.%1.%1").arg(fileName); - QList entriesForType = itemLibInfo->entriesForType(type.toLatin1()); - if (!entriesForType.isEmpty()) // should always be true, but just in case - QmlVisualNode::createQml3DNode(view(), entriesForType.at(0), m_canvas->activeScene()).modelNode(); - } + const QStringList added3DAssets = addedAssets.value(ComponentCoreConstants::add3DAssetsDisplayString); + for (const QString &assetPath : added3DAssets) { + QString fileName = QFileInfo(assetPath).baseName(); + fileName = fileName.at(0).toUpper() + fileName.mid(1); // capitalize first letter + QString type = QString("Quick3DAssets.%1.%1").arg(fileName); + QList entriesForType = itemLibInfo->entriesForType(type.toLatin1()); + if (!entriesForType.isEmpty()) { // should always be true, but just in case + QmlVisualNode::createQml3DNode(view(), entriesForType.at(0), + m_canvas->activeScene(), {}, false).modelNode(); + } + } + }); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index e7e3d69d6a3..842dee7e130 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -599,20 +599,24 @@ void FormEditorWidget::dropEvent(QDropEvent *dropEvent) ->viewManager().designerActionManager(); QHash addedAssets = actionManager.handleExternalAssetsDrop(dropEvent->mimeData()); - // Create Image components for added image assets - const QStringList addedImages = addedAssets.value(ComponentCoreConstants::addImagesDisplayString); - for (const QString &imgPath : addedImages) { - QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {}, - m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode()); - } + m_formEditorView->executeInTransaction("FormEditorWidget::dropEvent", [&] { + // Create Image components for added image assets + const QStringList addedImages = addedAssets.value(ComponentCoreConstants::addImagesDisplayString); + for (const QString &imgPath : addedImages) { + QmlItemNode::createQmlItemNodeFromImage(m_formEditorView, imgPath, {}, + m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode(), + false); + } - // Create Text components for added font assets - const QStringList addedFonts = addedAssets.value(ComponentCoreConstants::addFontsDisplayString); - for (const QString &fontPath : addedFonts) { - QString fontFamily = QFileInfo(fontPath).baseName(); - QmlItemNode::createQmlItemNodeFromFont(m_formEditorView, fontFamily, rootItemRect().center(), - m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode()); - } + // Create Text components for added font assets + const QStringList addedFonts = addedAssets.value(ComponentCoreConstants::addFontsDisplayString); + for (const QString &fontPath : addedFonts) { + QString fontFamily = QFileInfo(fontPath).baseName(); + QmlItemNode::createQmlItemNodeFromFont(m_formEditorView, fontFamily, rootItemRect().center(), + m_formEditorView->scene()->rootFormEditorItem()->qmlItemNode(), + false); + } + }); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/qmlvisualnode.h b/src/plugins/qmldesigner/designercore/include/qmlvisualnode.h index 114fef0d63c..af209245479 100644 --- a/src/plugins/qmldesigner/designercore/include/qmlvisualnode.h +++ b/src/plugins/qmldesigner/designercore/include/qmlvisualnode.h @@ -101,8 +101,9 @@ public: bool createInTransaction = true); static QmlVisualNode createQml3DNode(AbstractView *view, - const ItemLibraryEntry &itemLibraryEntry, - qint32 sceneRootId = -1, const QVector3D &position = {}); + const ItemLibraryEntry &itemLibraryEntry, + qint32 sceneRootId = -1, const QVector3D &position = {}, + bool createInTransaction = true); static NodeListProperty findSceneNodeProperty(AbstractView *view, qint32 sceneRootId); diff --git a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp index 02ecb64efde..c65f281f64a 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlitemnode.cpp @@ -174,7 +174,7 @@ QmlItemNode QmlItemNode::createQmlItemNodeFromFont(AbstractView *view, }; if (executeInTransaction) - view->executeInTransaction("QmlItemNode::createQmlItemNodeFromImage", doCreateQmlItemNodeFromFont); + view->executeInTransaction("QmlItemNode::createQmlItemNodeFromFont", doCreateQmlItemNodeFromFont); else doCreateQmlItemNodeFromFont(); diff --git a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp index 544471b03cc..f26c32ad780 100644 --- a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp @@ -365,14 +365,15 @@ QmlObjectNode QmlVisualNode::createQmlObjectNode(AbstractView *view, QmlVisualNode QmlVisualNode::createQml3DNode(AbstractView *view, const ItemLibraryEntry &itemLibraryEntry, - qint32 sceneRootId, const QVector3D &position) + qint32 sceneRootId, const QVector3D &position, + bool createInTransaction) { NodeAbstractProperty sceneNodeProperty = sceneRootId != -1 ? findSceneNodeProperty(view, sceneRootId) : view->rootModelNode().defaultNodeAbstractProperty(); QTC_ASSERT(sceneNodeProperty.isValid(), return {}); - return createQmlObjectNode(view, itemLibraryEntry, position, sceneNodeProperty).modelNode(); + return createQmlObjectNode(view, itemLibraryEntry, position, sceneNodeProperty, createInTransaction).modelNode(); } NodeListProperty QmlVisualNode::findSceneNodeProperty(AbstractView *view, qint32 sceneRootId) From 1311244832cee063c4bbf7afa2d8effe1e9c7cb8 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Thu, 28 Oct 2021 10:23:55 +0200 Subject: [PATCH 09/37] ClangCodeModel: Do not always consult clangd for the symbol name ... when doing "find usages". The symbol info request follows typedefs, which will result in confusing search window contents. So do the symbol info request only if the cursor is not on a normal identifier. Change-Id: I0d3bd8bfd47879c59e6656a4da73344406c97a21 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 73dfe21a8da..c5a2607bcc3 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -1302,15 +1302,25 @@ void ClangdClient::findUsages(TextDocument *document, const QTextCursor &cursor, const Utils::optional &replacement) { // Quick check: Are we even on anything searchable? - if (d->searchTermFromCursor(cursor).isEmpty()) + const QString searchTerm = d->searchTermFromCursor(cursor); + if (searchTerm.isEmpty()) return; - // Get the proper spelling of the search term from clang, so we can put it into the + const bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences(); + + // If it's a "normal" symbol, go right ahead. + if (searchTerm != "operator" && Utils::allOf(searchTerm, [](const QChar &c) { + return c.isLetterOrNumber() || c == '_'; + })) { + d->findUsages(document, cursor, searchTerm, replacement, categorize); + return; + } + + // Otherwise get the proper spelling of the search term from clang, so we can put it into the // search widget. const TextDocumentIdentifier docId(DocumentUri::fromFilePath(document->filePath())); const TextDocumentPositionParams params(docId, Range(cursor).start()); SymbolInfoRequest symReq(params); - const bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences(); symReq.setResponseCallback([this, doc = QPointer(document), cursor, replacement, categorize] (const SymbolInfoRequest::Response &response) { if (!doc) From a9bb006442e0a09dfd3b5597af501267737911d8 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Wed, 27 Oct 2021 16:35:51 +0200 Subject: [PATCH 10/37] QmlDesigner: Fix CharacterSection * Add enabled state to Weight and Emphasis label * Rearrange controls in character section Change-Id: Ie90935a09e1644f642abb232c7e44db7f3a6c8d8 Reviewed-by: Thomas Hartmann --- .../HelperWidgets/CharacterSection.qml | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml index 8dcee519706..127c7a38324 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CharacterSection.qml @@ -140,25 +140,6 @@ Section { ExpandingSpacer {} } - PropertyLabel { - text: qsTr("Weight") - tooltip: qsTr("Font's weight.") - } - - SecondColumnLayout { - ComboBox { - implicitWidth: StudioTheme.Values.singleControlColumnWidth - + StudioTheme.Values.actionIndicatorWidth - width: implicitWidth - backendValue: getBackendValue("weight") - model: ["Normal", "Light", "ExtraLight", "Thin", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"] - scope: "Font" - enabled: !styleNameComboBox.styleSet - } - - ExpandingSpacer {} - } - PropertyLabel { text: qsTr("Style name") tooltip: qsTr("Font's style.") @@ -267,7 +248,30 @@ Section { supportGradient: false } - PropertyLabel { text: qsTr("Emphasis") } + PropertyLabel { + text: qsTr("Weight") + tooltip: qsTr("Font's weight.") + enabled: !styleNameComboBox.styleSet + } + + SecondColumnLayout { + ComboBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + backendValue: getBackendValue("weight") + model: ["Normal", "Light", "ExtraLight", "Thin", "Medium", "DemiBold", "Bold", "ExtraBold", "Black"] + scope: "Font" + enabled: !styleNameComboBox.styleSet + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Emphasis") + enabled: !styleNameComboBox.styleSet + } FontStyleButtons { bold: root.boldStyle From a442d275fca72eaa8558d241f920e71bd06ae2b4 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 28 Oct 2021 13:29:03 +0200 Subject: [PATCH 11/37] Editor: hide old proposal if new proposal is empty amends 28447355bafb60733e61383adae04cb1b6e80b3c Change-Id: Ica1b95e205be4328e675714dbf81f813a76ec9a3 Reviewed-by: Christian Kandeler --- src/plugins/texteditor/codeassist/codeassistant.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/texteditor/codeassist/codeassistant.cpp b/src/plugins/texteditor/codeassist/codeassistant.cpp index 6aa1436c7dd..7224ef6906c 100644 --- a/src/plugins/texteditor/codeassist/codeassistant.cpp +++ b/src/plugins/texteditor/codeassist/codeassistant.cpp @@ -337,6 +337,7 @@ void CodeAssistantPrivate::displayProposal(IAssistProposal *newProposal, AssistR if (!newProposal->hasItemsToPropose(prefix, reason)) { if (newProposal->isCorrective(m_editorWidget)) newProposal->makeCorrection(m_editorWidget); + destroyContext(); return; } From e51ee5e0eecdedd6e1121a7d787c9928b1de2b60 Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Wed, 27 Oct 2021 14:44:29 +0200 Subject: [PATCH 12/37] GitHub Actions: Update Qt version to 6.2.1 Change-Id: I0b1bda8880620a17c51e43e5278dda5ced6be145 Reviewed-by: Eike Ziller --- .github/workflows/build_cmake.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 3efc8a7b464..94fbb314343 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -3,7 +3,7 @@ name: CMake Build Matrix on: [push, pull_request] env: - QT_VERSION: 6.2.0 + QT_VERSION: 6.2.1 CLANG_VERSION: 130 ELFUTILS_VERSION: 0.175 CMAKE_VERSION: 3.21.1 From b59c374217775e01815dd0346b0e94ab369a24e0 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 28 Oct 2021 15:11:34 +0200 Subject: [PATCH 13/37] Utils: sort the cursor before copying or inserting text The user shouldn't care about the order of the individual cursors inside the MultiTextCursor, so the order of selected texts should always be the same as in the document. Fixes: QTCREATORBUG-26494 Change-Id: I0d5199bda4e48f8482e20018b8f05020e16da3f6 Reviewed-by: Orgad Shaneh --- src/libs/utils/multitextcursor.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libs/utils/multitextcursor.cpp b/src/libs/utils/multitextcursor.cpp index 7a6e20f1b08..c06eb95f186 100644 --- a/src/libs/utils/multitextcursor.cpp +++ b/src/libs/utils/multitextcursor.cpp @@ -125,7 +125,9 @@ bool MultiTextCursor::hasSelection() const QString MultiTextCursor::selectedText() const { QString text; - for (const QTextCursor &cursor : m_cursors) { + QList cursors = m_cursors; + Utils::sort(cursors); + for (const QTextCursor &cursor : cursors) { const QString &cursorText = cursor.selectedText(); if (cursorText.isEmpty()) continue; @@ -169,7 +171,9 @@ void MultiTextCursor::insertText(const QString &text, bool selectNewText) lines.pop_back(); int index = 0; if (lines.count() == m_cursors.count()) { - for (QTextCursor &cursor : m_cursors) + QList cursors = m_cursors; + Utils::sort(cursors); + for (QTextCursor &cursor : cursors) insertAndSelect(cursor, lines.at(index++), selectNewText); m_cursors.last().endEditBlock(); return; From 761ce1feb1edf4f79413dade792773a607296f9b Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 12 Oct 2021 18:00:17 +0200 Subject: [PATCH 14/37] QmlJS: Proliferate FilePath use, part 2 Change-Id: I631df6ba5e782e2db9e03de4e5df843d15c19f37 Reviewed-by: Christian Stenger --- src/libs/qmljs/qmljsdocument.cpp | 4 ++ src/libs/qmljs/qmljsdocument.h | 3 +- src/libs/qmljs/qmljsmodelmanagerinterface.cpp | 28 ++++----- src/libs/qmljs/qmljsmodelmanagerinterface.h | 2 +- src/libs/qmljs/qmljsplugindumper.cpp | 59 +++++++++---------- src/libs/qmljs/qmljsplugindumper.h | 8 +-- 6 files changed, 53 insertions(+), 51 deletions(-) diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp index 67087570c2c..e7762e4f9c5 100644 --- a/src/libs/qmljs/qmljsdocument.cpp +++ b/src/libs/qmljs/qmljsdocument.cpp @@ -632,6 +632,10 @@ LibraryInfo Snapshot::libraryInfo(const QString &path) const return _libraries.value(QDir::cleanPath(path)); } +LibraryInfo Snapshot::libraryInfo(const Utils::FilePath &path) const +{ + return _libraries.value(path.cleanPath().toString()); +} void ModuleApiInfo::addToHash(QCryptographicHash &hash) const { diff --git a/src/libs/qmljs/qmljsdocument.h b/src/libs/qmljs/qmljsdocument.h index c6d4cf7dcea..199b4670502 100644 --- a/src/libs/qmljs/qmljsdocument.h +++ b/src/libs/qmljs/qmljsdocument.h @@ -256,7 +256,8 @@ public: Document::Ptr document(const QString &fileName) const; QList documentsInDirectory(const QString &path) const; - LibraryInfo libraryInfo(const QString &path) const; + LibraryInfo libraryInfo(const QString &path) const; // FIXME: Remove + LibraryInfo libraryInfo(const Utils::FilePath &path) const; Document::MutablePtr documentFromSource(const QString &code, const QString &fileName, diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index b7ed718a98d..1291b6525aa 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -684,19 +684,19 @@ void ModelManagerInterface::updateDocument(const Document::Ptr &doc) emit documentUpdated(doc); } -void ModelManagerInterface::updateLibraryInfo(const QString &path, const LibraryInfo &info) +void ModelManagerInterface::updateLibraryInfo(const FilePath &path, const LibraryInfo &info) { if (!info.pluginTypeInfoError().isEmpty()) qCDebug(qmljsLog) << "Dumping errors for " << path << ":" << info.pluginTypeInfoError(); { QMutexLocker locker(&m_mutex); - m_validSnapshot.insertLibraryInfo(path, info); - m_newestSnapshot.insertLibraryInfo(path, info); + m_validSnapshot.insertLibraryInfo(path.toString(), info); + m_newestSnapshot.insertLibraryInfo(path.toString(), info); } // only emit if we got new useful information if (info.isValid()) - emit libraryInfoUpdated(path, info); + emit libraryInfoUpdated(path.toString(), info); } static QStringList filesInDirectoryForLanguages(const QString &path, @@ -773,7 +773,7 @@ enum class LibraryStatus { Unknown }; -static LibraryStatus libraryStatus(const QString &path, const Snapshot &snapshot, +static LibraryStatus libraryStatus(const FilePath &path, const Snapshot &snapshot, QSet *newLibraries) { if (path.isEmpty()) @@ -782,7 +782,7 @@ static LibraryStatus libraryStatus(const QString &path, const Snapshot &snapshot const LibraryInfo &existingInfo = snapshot.libraryInfo(path); if (existingInfo.isValid()) return LibraryStatus::Accepted; - if (newLibraries->contains(path)) + if (newLibraries->contains(path.toString())) return LibraryStatus::Accepted; // if we looked at the path before, done return existingInfo.wasScanned() @@ -790,7 +790,7 @@ static LibraryStatus libraryStatus(const QString &path, const Snapshot &snapshot : LibraryStatus::Unknown; } -static bool findNewQmlApplicationInPath(const QString &path, +static bool findNewQmlApplicationInPath(const FilePath &path, const Snapshot &snapshot, ModelManagerInterface *modelManager, QSet *newLibraries) @@ -803,8 +803,8 @@ static bool findNewQmlApplicationInPath(const QString &path, QString qmltypesFile; - QDir dir(path); - QDirIterator it(path, QStringList { "*.qmltypes" }, QDir::Files); + QDir dir(path.toString()); + QDirIterator it(path.toString(), QStringList { "*.qmltypes" }, QDir::Files); if (!it.hasNext()) return false; @@ -828,7 +828,7 @@ static bool findNewQmlLibraryInPath(const QString &path, QSet *newLibraries, bool ignoreMissing) { - switch (libraryStatus(path, snapshot, newLibraries)) { + switch (libraryStatus(FilePath::fromString(path), snapshot, newLibraries)) { case LibraryStatus::Accepted: return true; case LibraryStatus::Rejected: return false; default: break; @@ -839,7 +839,7 @@ static bool findNewQmlLibraryInPath(const QString &path, if (!qmldirFile.exists()) { if (!ignoreMissing) { LibraryInfo libraryInfo(LibraryInfo::NotFound); - modelManager->updateLibraryInfo(path, libraryInfo); + modelManager->updateLibraryInfo(FilePath::fromString(path), libraryInfo); } return false; } @@ -858,7 +858,7 @@ static bool findNewQmlLibraryInPath(const QString &path, const QString libraryPath = QFileInfo(qmldirFile).absolutePath(); newLibraries->insert(libraryPath); - modelManager->updateLibraryInfo(libraryPath, LibraryInfo(qmldirParser)); + modelManager->updateLibraryInfo(FilePath::fromString(libraryPath), LibraryInfo(qmldirParser)); modelManager->loadPluginTypes(QFileInfo(libraryPath).canonicalFilePath(), libraryPath, QString(), QString()); @@ -1252,7 +1252,7 @@ void ModelManagerInterface::updateImportPaths() for (const Document::Ptr &doc : qAsConst(snapshot)) findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries); for (const QString &path : qAsConst(allApplicationDirectories)) - findNewQmlApplicationInPath(path, snapshot, this, &newLibraries); + findNewQmlApplicationInPath(FilePath::fromString(path), snapshot, this, &newLibraries); updateSourceFiles(importedFiles, true); @@ -1433,7 +1433,7 @@ LibraryInfo ModelManagerInterface::builtins(const Document::Ptr &doc) const { const ProjectInfo info = projectInfoForPath(doc->fileName()); if (!info.qtQmlPath.isEmpty()) - return m_validSnapshot.libraryInfo(info.qtQmlPath.toString()); + return m_validSnapshot.libraryInfo(info.qtQmlPath); return LibraryInfo(); } diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index 1fc9260ae94..5a4f711a1be 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -156,7 +156,7 @@ public: void updateProjectInfo(const ProjectInfo &pinfo, ProjectExplorer::Project *p); void updateDocument(const QmlJS::Document::Ptr& doc); - void updateLibraryInfo(const QString &path, const QmlJS::LibraryInfo &info); + void updateLibraryInfo(const Utils::FilePath &path, const QmlJS::LibraryInfo &info); void emitDocumentChangedOnDisk(QmlJS::Document::Ptr doc); void updateQrcFile(const QString &path); ProjectInfo projectInfoForPath(const QString &path) const; diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index c8b80fafa56..29c6e67d12e 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -89,25 +89,23 @@ void PluginDumper::onLoadBuiltinTypes(const QmlJS::ModelManagerInterface::Projec if (info.qmlDumpPath.isEmpty() || info.qtQmlPath.isEmpty()) return; - // FIXME: This doesn't work for non-local paths. - const QString importsPath = QDir::cleanPath(info.qtQmlPath.toString()); - if (m_runningQmldumps.values().contains(importsPath)) + if (m_runningQmldumps.values().contains(info.qmlDumpPath)) return; LibraryInfo builtinInfo; if (!force) { const Snapshot snapshot = m_modelManager->snapshot(); - builtinInfo = snapshot.libraryInfo(info.qtQmlPath.toString()); + builtinInfo = snapshot.libraryInfo(info.qtQmlPath); if (builtinInfo.isValid()) return; } builtinInfo = LibraryInfo(LibraryInfo::Found); - m_modelManager->updateLibraryInfo(info.qtQmlPath.toString(), builtinInfo); + m_modelManager->updateLibraryInfo(info.qtQmlPath, builtinInfo); // prefer QTDIR/qml/builtins.qmltypes if available const QString builtinQmltypesPath = info.qtQmlPath.toString() + QLatin1String("/builtins.qmltypes"); if (QFile::exists(builtinQmltypesPath)) { - loadQmltypesFile(QStringList(builtinQmltypesPath), info.qtQmlPath.toString(), builtinInfo); + loadQmltypesFile(QStringList(builtinQmltypesPath), info.qtQmlPath, builtinInfo); return; } @@ -124,7 +122,7 @@ static QString makeAbsolute(const QString &path, const QString &base) void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString &importPath, const QString &importUri, const QString &importVersion) { - const QString canonicalLibraryPath = QDir::cleanPath(libraryPath); + const FilePath canonicalLibraryPath = FilePath::fromUserInput(libraryPath).cleanPath(); if (m_runningQmldumps.values().contains(canonicalLibraryPath)) return; const Snapshot snapshot = m_modelManager->snapshot(); @@ -135,7 +133,7 @@ void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString & // avoid inserting the same plugin twice int index; for (index = 0; index < m_plugins.size(); ++index) { - if (m_plugins.at(index).qmldirPath == libraryPath) + if (m_plugins.at(index).qmldirPath == canonicalLibraryPath) break; } if (index == m_plugins.size()) @@ -148,10 +146,10 @@ void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString & plugin.importVersion = importVersion; // add default qmltypes file if it exists - QDirIterator it(canonicalLibraryPath, QStringList { "*.qmltypes" }, QDir::Files); + QDirIterator it(canonicalLibraryPath.toString(), QStringList { "*.qmltypes" }, QDir::Files); while (it.hasNext()) { - const QString defaultQmltypesPath = makeAbsolute(it.next(), canonicalLibraryPath); + const QString defaultQmltypesPath = makeAbsolute(it.next(), canonicalLibraryPath.toString()); if (!plugin.typeInfoPaths.contains(defaultQmltypesPath)) plugin.typeInfoPaths += defaultQmltypesPath; @@ -159,14 +157,14 @@ void PluginDumper::onLoadPluginTypes(const QString &libraryPath, const QString & // add typeinfo files listed in qmldir foreach (const QString &typeInfo, libraryInfo.typeInfos()) { - QString pathNow = makeAbsolute(typeInfo, canonicalLibraryPath); + QString pathNow = makeAbsolute(typeInfo, canonicalLibraryPath.toString()); if (!plugin.typeInfoPaths.contains(pathNow) && QFile::exists(pathNow)) plugin.typeInfoPaths += pathNow; } // watch plugin libraries foreach (const QmlDirParser::Plugin &plugin, snapshot.libraryInfo(canonicalLibraryPath).plugins()) { - const QString pluginLibrary = resolvePlugin(canonicalLibraryPath, plugin.path, plugin.name); + const QString pluginLibrary = resolvePlugin(canonicalLibraryPath.toString(), plugin.path, plugin.name); if (!pluginLibrary.isEmpty()) { if (!pluginWatcher()->watchesFile(pluginLibrary)) pluginWatcher()->addFile(pluginLibrary, Utils::FileSystemWatcher::WatchModifiedDate); @@ -195,26 +193,25 @@ void PluginDumper::dumpAllPlugins() } } -static QString noTypeinfoError(const QString &libraryPath) +static QString noTypeinfoError(const FilePath &libraryPath) { return PluginDumper::tr("QML module does not contain information about components contained in plugins.\n\n" "Module path: %1\n" "See \"Using QML Modules with Plugins\" in the documentation.").arg( - libraryPath); + libraryPath.toUserOutput()); } -static QString qmldumpErrorMessage(const QString &libraryPath, const QString &error) +static QString qmldumpErrorMessage(const FilePath &libraryPath, const QString &error) { - return noTypeinfoError(libraryPath) + QLatin1String("\n\n") + + return noTypeinfoError(libraryPath) + "\n\n" + PluginDumper::tr("Automatic type dump of QML module failed.\nErrors:\n%1"). arg(error) + QLatin1Char('\n'); } -static QString qmldumpFailedMessage(const QString &libraryPath, const QString &error) +static QString qmldumpFailedMessage(const FilePath &libraryPath, const QString &error) { - QString firstLines = - QStringList(error.split(QLatin1Char('\n')).mid(0, 10)).join(QLatin1Char('\n')); - return noTypeinfoError(libraryPath) + QLatin1String("\n\n") + + QString firstLines = QStringList(error.split('\n').mid(0, 10)).join('\n'); + return noTypeinfoError(libraryPath) + "\n\n" + PluginDumper::tr("Automatic type dump of QML module failed.\n" "First 10 lines or errors:\n" "\n" @@ -224,11 +221,11 @@ static QString qmldumpFailedMessage(const QString &libraryPath, const QString &e ).arg(firstLines); } -static void printParseWarnings(const QString &libraryPath, const QString &warning) +static void printParseWarnings(const FilePath &libraryPath, const QString &warning) { ModelManagerInterface::writeWarning( PluginDumper::tr("Warnings while parsing QML type information of %1:\n" - "%2").arg(libraryPath, warning)); + "%2").arg(libraryPath.toUserOutput(), warning)); } static QString qmlPluginDumpErrorMessage(QtcProcess *process) @@ -269,7 +266,7 @@ void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process) { process->deleteLater(); - const QString libraryPath = m_runningQmldumps.take(process); + const FilePath libraryPath = m_runningQmldumps.take(process); if (libraryPath.isEmpty()) return; const Snapshot snapshot = m_modelManager->snapshot(); @@ -298,7 +295,7 @@ void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process) CppQmlTypesInfo infos; CppQmlTypesLoader::parseQmlTypeDescriptions(output, &infos.objectsList, &infos.moduleApis, &infos.dependencies, &infos.error, &infos.warning, - QLatin1String("')); + "'); future.reportFinished(&infos); }); m_modelManager->addFuture(future); @@ -338,13 +335,13 @@ void PluginDumper::qmlPluginTypeDumpError(QtcProcess *process) { process->deleteLater(); - const QString libraryPath = m_runningQmldumps.take(process); + const FilePath libraryPath = m_runningQmldumps.take(process); if (libraryPath.isEmpty()) return; const QString errorMessages = qmlPluginDumpErrorMessage(process); const Snapshot snapshot = m_modelManager->snapshot(); LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath); - if (!libraryPath.endsWith(QLatin1String("private"), Qt::CaseInsensitive)) + if (!libraryPath.path().endsWith(QLatin1String("private"), Qt::CaseInsensitive)) ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages)); libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, qmldumpFailedMessage(libraryPath, errorMessages)); libraryInfo.updateFingerprint(); @@ -564,7 +561,7 @@ static void applyQt515MissingImportWorkaround(const QString &path, LibraryInfo & } void PluginDumper::prepareLibraryInfo(LibraryInfo &libInfo, - const QString &libraryPath, + const FilePath &libraryPath, const QStringList &deps, const QStringList &errors, const QStringList &warnings, @@ -588,13 +585,13 @@ void PluginDumper::prepareLibraryInfo(LibraryInfo &libInfo, if (!warnings.isEmpty()) printParseWarnings(libraryPath, warnings.join(QLatin1String("\n"))); - applyQt515MissingImportWorkaround(libraryPath, libInfo); + applyQt515MissingImportWorkaround(libraryPath.toString(), libInfo); libInfo.updateFingerprint(); } void PluginDumper::loadQmltypesFile(const QStringList &qmltypesFilePaths, - const QString &libraryPath, + const FilePath &libraryPath, QmlJS::LibraryInfo libraryInfo) { Utils::onFinished(loadQmlTypeDescription(qmltypesFilePaths), this, [=](const QFuture &typesFuture) @@ -640,7 +637,7 @@ void PluginDumper::runQmlDump(const ModelManagerInterface::ProjectInfo &info, connect(process, &QtcProcess::finished, this, [this, process] { qmlPluginTypeDumpDone(process); }); connect(process, &QtcProcess::errorOccurred, this, [this, process] { qmlPluginTypeDumpError(process); }); process->start(); - m_runningQmldumps.insert(process, importPath.toString()); + m_runningQmldumps.insert(process, importPath); } void PluginDumper::dump(const Plugin &plugin) @@ -686,7 +683,7 @@ void PluginDumper::dump(const Plugin &plugin) args << plugin.importUri; args << plugin.importVersion; args << (plugin.importPath.isEmpty() ? QLatin1String(".") : plugin.importPath); - runQmlDump(info, args, FilePath::fromString(plugin.qmldirPath)); + runQmlDump(info, args, plugin.qmldirPath); } /*! diff --git a/src/libs/qmljs/qmljsplugindumper.h b/src/libs/qmljs/qmljsplugindumper.h index 98aadfbce40..4f0ca1ce321 100644 --- a/src/libs/qmljs/qmljsplugindumper.h +++ b/src/libs/qmljs/qmljsplugindumper.h @@ -65,7 +65,7 @@ private: private: class Plugin { public: - QString qmldirPath; + Utils::FilePath qmldirPath; QString importPath; QString importUri; QString importVersion; @@ -98,7 +98,7 @@ private: QSharedPointer> visited) const; void loadQmltypesFile(const QStringList &qmltypesFilePaths, - const QString &libraryPath, + const Utils::FilePath &libraryPath, QmlJS::LibraryInfo libraryInfo); QString resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, const QString &baseName); @@ -109,7 +109,7 @@ private: private: Utils::FileSystemWatcher *pluginWatcher(); void prepareLibraryInfo(LibraryInfo &libInfo, - const QString &libraryPath, + const Utils::FilePath &libraryPath, const QStringList &deps, const QStringList &errors, const QStringList &warnings, @@ -118,7 +118,7 @@ private: ModelManagerInterface *m_modelManager; Utils::FileSystemWatcher *m_pluginWatcher; - QHash m_runningQmldumps; + QHash m_runningQmldumps; QList m_plugins; QHash m_libraryToPluginIndex; QHash m_qtToInfo; From 4ad8890b885b88a2b4fd670076c4d77f20708590 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 28 Oct 2021 17:21:39 +0200 Subject: [PATCH 15/37] QmlDesigner: Use AuxiliaryData as cache for NodeHints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Evaluating the NodeHints can become a bottle-neck in large scenes. The columnCount depends on the filter and is called many times during painting. For large scenes with many nodes this becomes a real bottle-neck turning QDS unusable. Task-number: QDS-5277 Change-Id: Ifbd9ec8024e30541bfaafba4c44db47f5c426bfc Reviewed-by: Henning Gründl --- .../components/navigator/navigatortreemodel.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index e07f300bffc..aa04d232876 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -316,7 +316,12 @@ QList filteredList(const NodeListProperty &property, bool filter, boo if (filter) { list.append(Utils::filtered(property.toModelNodeList(), [] (const ModelNode &arg) { - return QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator(); + const char auxProp[] = "showInNavigator@Internal"; + if (arg.hasAuxiliaryData(auxProp)) + return arg.auxiliaryData(auxProp).toBool(); + const bool value = QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator(); + arg.setAuxiliaryData(auxProp, value); + return value; })); } else { list = property.toModelNodeList(); From dc9dc6b00204a5fef3542dc9a1f56f533353e058 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 28 Oct 2021 15:50:11 +0300 Subject: [PATCH 16/37] QmlDesigner: Adjust ComponentTextModifier offsets on doc text change ComponentTextModifier offsets were set at modifier creation time, and were not adjusted for changes on the document before the subcomponent code. Added rudimentary change detection logic for code additions and removals before subcomponent code and adjust offsets accordingly. Fixes: QDS-5305 Change-Id: I816adc1fc867b7135b992fb50a5d96e2cfd3f0d2 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Bot Reviewed-by: Thomas Hartmann --- .../include/componenttextmodifier.h | 3 ++ .../model/componenttextmodifier.cpp | 47 ++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h index d870f29622a..d35a4c149ee 100644 --- a/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h +++ b/src/plugins/qmldesigner/designercore/include/componenttextmodifier.h @@ -62,11 +62,14 @@ public: { return false; } private: + void handleOriginalTextChanged(); + TextModifier *m_originalModifier; int m_componentStartOffset; int m_componentEndOffset; int m_rootStartOffset; int m_startLength; + QString m_originalText; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp index 5f984a1f348..42dbbdd2a0e 100644 --- a/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp +++ b/src/plugins/qmldesigner/designercore/model/componenttextmodifier.cpp @@ -33,10 +33,13 @@ ComponentTextModifier::ComponentTextModifier(TextModifier *originalModifier, int m_componentEndOffset(componentEndOffset), m_rootStartOffset(rootStartOffset) { - connect(m_originalModifier, &TextModifier::textChanged, this, &TextModifier::textChanged); + connect(m_originalModifier, &TextModifier::textChanged, + this, &ComponentTextModifier::handleOriginalTextChanged); connect(m_originalModifier, &TextModifier::replaced, this, &TextModifier::replaced); connect(m_originalModifier, &TextModifier::moved, this, &TextModifier::moved); + + m_originalText = m_originalModifier->text(); } ComponentTextModifier::~ComponentTextModifier() = default; @@ -146,3 +149,45 @@ void ComponentTextModifier::reactivateChangeSignals() { m_originalModifier->reactivateChangeSignals(); } + +void ComponentTextModifier::handleOriginalTextChanged() +{ + // Update offsets when original text changes, if necessary + + // Detect and adjust for removal/addition of unrelated text before the subcomponent code, + // as that can happen even without user editing the text (e.g. whitespace removal at save time) + + const QString currentText = m_originalModifier->text(); + + if (m_originalText.left(m_componentStartOffset) != currentText.left(m_componentStartOffset)) { + // Subcomponent item id is the only reliable indicator for adjustment + const int idIndex = m_originalText.indexOf("id:", m_componentStartOffset); + if (idIndex != -1 && idIndex < m_componentEndOffset) { + int newLineIndex = m_originalText.indexOf('\n', idIndex); + if (newLineIndex != -1) { + const QString checkLine = m_originalText.mid(idIndex, newLineIndex - idIndex); + int lineIndex = currentText.indexOf(checkLine); + if (lineIndex != -1) { + // Paranoia check - This shouldn't happen except when modifying text manually, + // but it's possible something was inserted between id and start + // of the component, which would throw off the calculation, so check that + // the first line is still correct even with new offset. + const int diff = idIndex - lineIndex; + newLineIndex = m_originalText.indexOf('\n', m_componentStartOffset); + if (newLineIndex != -1) { + const QString firstLine = m_originalText.mid(m_componentStartOffset, + newLineIndex - m_componentStartOffset); + const int newStart = m_componentStartOffset - diff; + if (firstLine == currentText.mid(newStart, firstLine.size())) { + m_componentEndOffset -= diff; + m_componentStartOffset = newStart; + m_originalText = currentText; + } + } + } + } + } + } + + emit textChanged(); +} From c3a11939697f9b9fc92375d5f100d8f8d75a7bd8 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 27 Oct 2021 15:52:20 +0200 Subject: [PATCH 17/37] TextEditor: Add highlighting category for namespaces ... and make use of it in the built-in code model and with clangd. Task-number: QTCREATORBUG-16580 Change-Id: I8c331f56aa1bbf91c9f768be82a779a72f40c4c7 Reviewed-by: David Schulz --- share/qtcreator/styles/grayscale.xml | 1 + src/plugins/clangcodemodel/clangdclient.cpp | 2 +- .../clangcodemodel/test/clangdtests.cpp | 13 ++--- src/plugins/cppeditor/cppchecksymbols.cpp | 14 ++++- src/plugins/cppeditor/semantichighlighter.cpp | 1 + src/plugins/cppeditor/semantichighlighter.h | 1 + src/plugins/texteditor/fontsettings.cpp | 4 ++ .../texteditor/texteditorconstants.cpp | 1 + src/plugins/texteditor/texteditorconstants.h | 1 + src/plugins/texteditor/texteditorsettings.cpp | 2 + .../checksymbols/tst_checksymbols.cpp | 51 ++++++++++--------- 11 files changed, 57 insertions(+), 34 deletions(-) diff --git a/share/qtcreator/styles/grayscale.xml b/share/qtcreator/styles/grayscale.xml index 39dabbff691..09a09f1ba93 100644 --- a/share/qtcreator/styles/grayscale.xml +++ b/share/qtcreator/styles/grayscale.xml @@ -35,6 +35,7 @@