From 1c90a9631b6f2c16131544466aabd52d272ea3cf Mon Sep 17 00:00:00 2001 From: Sergey Belyashov Date: Wed, 19 Oct 2016 11:16:11 +0300 Subject: [PATCH 01/47] Update Russian translation Change-Id: I1353d68a2a07a031446ebe2b2ae4eb45f07f06e3 Reviewed-by: Denis Shienkov Reviewed-by: Oswald Buddenhagen --- share/qtcreator/translations/qtcreator_ru.ts | 48 ++++++++++++++++---- 1 file changed, 40 insertions(+), 8 deletions(-) diff --git a/share/qtcreator/translations/qtcreator_ru.ts b/share/qtcreator/translations/qtcreator_ru.ts index 7b44ddb9e3e..5d63556c128 100644 --- a/share/qtcreator/translations/qtcreator_ru.ts +++ b/share/qtcreator/translations/qtcreator_ru.ts @@ -19865,6 +19865,38 @@ Ids must begin with a lowercase letter. iOS tool Error %1 Ошибка %1 утилиты iOS + + Application install on Simulator failed. %1 + Не удалось установить приложение на эмулятор. %1 + + + Application install on Simulator failed. Simulator not running. + Не удалось установить приложение на эмулятор. Он не запущен. + + + Application launch on Simulator failed. Invalid Bundle path %1 + Запуск приложения на эмуляторе не удался. Неверный путь пакета %1 + + + Spawning the Application process on Simulator failed. + Не удалось породить процесс приложения на эмуляторе. + + + Application launch on Simulator failed. Simulator not running. + Не удалось запустить приложение на эмуляторе. Он не запущен. + + + Application launch on Simulator failed. %1 + Запуск приложения на эмуляторе не удался. %1 + + + Spawning the Application process on Simulator failed. Spawning timed out. + Не удалось породить процесс приложения на эмуляторе. Время порождения истекло. + + + Simulator application process error %1 + Приложение из эмулятора вернуло ошибку %1 + IosDeployStepWidget @@ -21336,14 +21368,14 @@ Ids must begin with a lowercase letter. Nim::NimCompilerBuildStepFactory Nim Compiler Build Step - Этап сборки компилятора Nim + Этап сборки компилятора Nim Nim::NimCompilerCleanStep Nim Clean Step - Этап очистки компилятора Nim + Этап очистки компилятора Nim Build directory "%1" does not exist. @@ -21432,28 +21464,28 @@ Ids must begin with a lowercase letter. NimCompilerBuildStep Nim Compiler Build Step - Этап сборки компилятора Nim + Этап сборки компилятора Nim NimCompilerBuildStepConfigWidget Nim build step - Этап сборки Nim + Этап сборки Nim NimCompilerCleanStepFactory Nim Compiler Clean Step - Этап очистки компилятора Nim + Этап очистки компилятора Nim NimCompilerCleanStepWidget Nim clean step - Этап очистки Nim + Этап очистки Nim @@ -36642,11 +36674,11 @@ In addition, Shift+Enter inserts an escape character at the cursor position and Remove the automatically inserted character if the trigger is deleted by backspace after the completion. - Удалять автоматически вставленный символ, если флаг удалён бекспейсом после дополнения. + Удалять автоматически вставленный символ, если флаг удалён бекспейсом после дополнения. Remove automatically inserted text on backspace - Удалять автоматически вставленный текст по бекспейсу + Удалять автоматически вставленный текст по бекспейсу Documentation Comments From c1e600a41dd8454a2a3275e95d6ab2b5a4bf6438 Mon Sep 17 00:00:00 2001 From: Andy Shaw Date: Fri, 2 Sep 2016 15:48:16 +0200 Subject: [PATCH 02/47] Remove the qt keyword from CONFIG This is already implicitly included, however since the placement of it can interfere with the qtquickcompiler, it should be removed. Change-Id: I270fa0093ad8a7739f4f25bbef477560003e2d01 Reviewed-by: Oswald Buddenhagen --- .../qtcreator/templates/wizards/qtquick2-extension/project.pro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/templates/wizards/qtquick2-extension/project.pro b/share/qtcreator/templates/wizards/qtquick2-extension/project.pro index cd8c68954c6..36df40ced98 100644 --- a/share/qtcreator/templates/wizards/qtquick2-extension/project.pro +++ b/share/qtcreator/templates/wizards/qtquick2-extension/project.pro @@ -1,7 +1,7 @@ TEMPLATE = lib TARGET = %ProjectName% QT += qml quick -CONFIG += qt plugin c++11 +CONFIG += plugin c++11 TARGET = $$qtLibraryTarget($$TARGET) uri = %Uri% From 5a2001f730b78a4f71ee883c1e33c1ef0c1a4531 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 24 Oct 2016 15:53:37 +0200 Subject: [PATCH 03/47] Android: Add C toolchains This should fix kits complaining about wrongly set C compilers and ABI incompatibility between C and C++ compilers. Task-number: QTCREATORBUG-17165 Task-number: QTCREATORBUG-17166 Change-Id: Ia002490b471e0f5306c3a76b27158869920452ed Reviewed-by: BogDan Vatra --- src/plugins/android/androidconfigurations.cpp | 86 +++++++++++-------- src/plugins/android/androidconfigurations.h | 6 +- src/plugins/android/androidsettingswidget.cpp | 18 ++-- src/plugins/android/androidtoolchain.cpp | 62 +++++++------ src/plugins/android/androidtoolchain.h | 4 +- 5 files changed, 97 insertions(+), 79 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index 191555b948b..e68f0f3473e 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -507,9 +507,12 @@ FileName AndroidConfig::toolPath(const Abi &abi, const QString &ndkToolChainVers .arg(toolsPrefix(abi))); } -FileName AndroidConfig::gccPath(const Abi &abi, const QString &ndkToolChainVersion) const +FileName AndroidConfig::gccPath(const Abi &abi, ToolChain::Language lang, + const QString &ndkToolChainVersion) const { - return toolPath(abi, ndkToolChainVersion).appendString(QLatin1String("-gcc" QTC_HOST_EXE_SUFFIX)); + const QString tool + = HostOsInfo::withExecutableSuffix(QString::fromLatin1(lang == ToolChain::Language::C ? "-gcc" : "-g++")); + return toolPath(abi, ndkToolChainVersion).appendString(tool); } FileName AndroidConfig::gdbPath(const Abi &abi, const QString &ndkToolChainVersion) const @@ -1198,24 +1201,32 @@ QString AndroidConfigurations::defaultDevice(Project *project, const QString &ab return map.value(abi); } -static bool equalKits(Kit *a, Kit *b) +static bool matchToolChain(const ToolChain *atc, const ToolChain *btc) +{ + if (atc == btc) + return true; + + if (!atc || !btc) + return false; + + if (atc->typeId() != Constants::ANDROID_TOOLCHAIN_ID || btc->typeId() != Constants::ANDROID_TOOLCHAIN_ID) + return false; + + auto aatc = static_cast(atc); + auto abtc = static_cast(btc); + return aatc->ndkToolChainVersion() == abtc->ndkToolChainVersion() + && aatc->targetAbi() == abtc->targetAbi(); +} + +static bool matchKits(const Kit *a, const Kit *b) { if (QtSupport::QtKitInformation::qtVersion(a) != QtSupport::QtKitInformation::qtVersion(b)) return false; - ToolChain *atc = ToolChainKitInformation::toolChain(a, ToolChain::Language::Cxx); - ToolChain *btc = ToolChainKitInformation::toolChain(b, ToolChain::Language::Cxx); - if (atc == btc) - return true; - if (!atc || atc->typeId() != Constants::ANDROID_TOOLCHAIN_ID) - return false; - if (!btc || btc->typeId() != Constants::ANDROID_TOOLCHAIN_ID) - return false; - AndroidToolChain *aatc = static_cast(atc); - AndroidToolChain *bbtc = static_cast(btc); - if (aatc->ndkToolChainVersion() == bbtc->ndkToolChainVersion() - && aatc->targetAbi() == bbtc->targetAbi()) - return true; - return false; + + return matchToolChain(ToolChainKitInformation::toolChain(a, ToolChain::Language::Cxx), + ToolChainKitInformation::toolChain(b, ToolChain::Language::Cxx)) + && matchToolChain(ToolChainKitInformation::toolChain(a, ToolChain::Language::C), + ToolChainKitInformation::toolChain(b, ToolChain::Language::C)); } void AndroidConfigurations::registerNewToolChains() @@ -1243,23 +1254,7 @@ void AndroidConfigurations::removeOldToolChains() void AndroidConfigurations::updateAutomaticKitList() { - QList toolchains; - if (AndroidConfigurations::currentConfig().automaticKitCreation()) { - // having a empty toolchains list will remove all autodetected kits for android - // exactly what we want in that case - foreach (ToolChain *tc, ToolChainManager::toolChains()) { - if (!tc->isAutoDetected()) - continue; - if (tc->typeId() != Constants::ANDROID_TOOLCHAIN_ID) - continue; - if (!tc->isValid()) // going to be deleted - continue; - toolchains << static_cast(tc); - } - } - QList existingKits; - foreach (Kit *k, KitManager::kits()) { if (DeviceTypeKitInformation::deviceTypeId(k) != Core::Id(Constants::ANDROID_DEVICE_TYPE)) continue; @@ -1305,15 +1300,29 @@ void AndroidConfigurations::updateAutomaticKitList() // register new kits QList newKits; - foreach (AndroidToolChain *tc, toolchains) { - if (tc->isSecondaryToolChain()) + const QList tmp = Utils::filtered(ToolChainManager::toolChains(), [](ToolChain *tc) { + return tc->isAutoDetected() + && tc->isValid() + && tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID + && !static_cast(tc)->isSecondaryToolChain(); + }); + const QList toolchains = Utils::transform(tmp, [](ToolChain *tc) { + return static_cast(tc); + }); + for (AndroidToolChain *tc : toolchains) { + if (tc->isSecondaryToolChain() || tc->language() != ToolChain::Language::Cxx) continue; + const QList allLanguages = Utils::filtered(toolchains, + [tc](AndroidToolChain *otherTc) { + return tc->targetAbi() == otherTc->targetAbi(); + }); QList qtVersions = qtVersionsForArch.value(tc->targetAbi()); foreach (QtSupport::BaseQtVersion *qt, qtVersions) { Kit *newKit = new Kit; newKit->setAutoDetected(true); DeviceTypeKitInformation::setDeviceTypeId(newKit, Core::Id(Constants::ANDROID_DEVICE_TYPE)); - ToolChainKitInformation::setToolChain(newKit, tc); + for (AndroidToolChain *tc : allLanguages) + ToolChainKitInformation::setToolChain(newKit, tc); QtSupport::QtKitInformation::setQtVersion(newKit, qt); DeviceKitInformation::setDevice(newKit, device); @@ -1337,12 +1346,13 @@ void AndroidConfigurations::updateAutomaticKitList() Kit *existingKit = existingKits.at(i); for (int j = 0; j < newKits.count(); ++j) { Kit *newKit = newKits.at(j); - if (equalKits(existingKit, newKit)) { + if (matchKits(existingKit, newKit)) { // Kit is already registered, nothing to do newKits.removeAt(j); existingKits.at(i)->makeSticky(); existingKits.removeAt(i); - ToolChainKitInformation::setToolChain(existingKit, ToolChainKitInformation::toolChain(newKit, ToolChain::Language::Cxx)); + for (ToolChain::Language lang : ToolChain::allLanguages()) + ToolChainKitInformation::setToolChain(existingKit, ToolChainKitInformation::toolChain(newKit, lang)); KitManager::deleteKit(newKit); j = newKits.count(); } diff --git a/src/plugins/android/androidconfigurations.h b/src/plugins/android/androidconfigurations.h index 6a73c766951..1f6b2f6d07e 100644 --- a/src/plugins/android/androidconfigurations.h +++ b/src/plugins/android/androidconfigurations.h @@ -27,6 +27,8 @@ #include "android_global.h" +#include + #include #include #include @@ -126,7 +128,9 @@ public: Utils::FileName emulatorToolPath() const; - Utils::FileName gccPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const; + Utils::FileName gccPath(const ProjectExplorer::Abi &abi, + ProjectExplorer::ToolChain::Language lang, + const QString &ndkToolChainVersion) const; Utils::FileName gdbPath(const ProjectExplorer::Abi &abi, const QString &ndkToolChainVersion) const; Utils::FileName keytoolPath() const; diff --git a/src/plugins/android/androidsettingswidget.cpp b/src/plugins/android/androidsettingswidget.cpp index 50befd044fc..f5bafe43feb 100644 --- a/src/plugins/android/androidsettingswidget.cpp +++ b/src/plugins/android/androidsettingswidget.cpp @@ -314,6 +314,8 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode) // Check for a gdb with a broken python QStringList gdbPaths; foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) { + if (ati.language == ProjectExplorer::ToolChain::Language::C) + continue; // we only check the arm gdbs, that's indicative enough if (ati.abi.architecture() != ProjectExplorer::Abi::ArmArchitecture) continue; @@ -329,8 +331,10 @@ void AndroidSettingsWidget::check(AndroidSettingsWidget::Mode mode) // See if we have qt versions for those toolchains QSet toolchainsForAbi; - foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) - toolchainsForAbi.insert(ati.abi); + foreach (const AndroidToolChainFactory::AndroidToolChainInformation &ati, compilerPaths) { + if (ati.language == ProjectExplorer::ToolChain::Language::Cxx) + toolchainsForAbi.insert(ati.abi); + } QSet qtVersionsForAbi; foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::unsortedVersions()) { @@ -496,16 +500,6 @@ void AndroidSettingsWidget::saveSettings() AndroidConfigurations::setConfig(m_androidConfig); } -int indexOf(const QList &list, const Utils::FileName &f) -{ - int end = list.count(); - for (int i = 0; i < end; ++i) { - if (list.at(i).compilerCommand == f) - return i; - } - return -1; -} - void AndroidSettingsWidget::sdkLocationEditingFinished() { m_androidConfig.setSdkLocation(Utils::FileName::fromUserInput(m_ui->SDKLocationPathChooser->rawPath())); diff --git a/src/plugins/android/androidtoolchain.cpp b/src/plugins/android/androidtoolchain.cpp index f89b6330715..6794d85d3e1 100644 --- a/src/plugins/android/androidtoolchain.cpp +++ b/src/plugins/android/androidtoolchain.cpp @@ -302,16 +302,17 @@ QList AndroidToolChainFact int idx = versionRegExp.indexIn(fileName); if (idx == -1) continue; - AndroidToolChainInformation ati; - ati.version = fileName.mid(idx + 1); - QString platform = fileName.left(idx); - ati.abi = AndroidConfig::abiForToolChainPrefix(platform); - if (ati.abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported - continue; - // AndroidToolChain *tc = new AndroidToolChain(arch, version, true); - ati.compilerCommand = AndroidConfigurations::currentConfig().gccPath(ati.abi, ati.version); - // tc->setCompilerCommand(compilerPath); - result.append(ati); + for (const ToolChain::Language lang : { ToolChain::Language::Cxx, ToolChain::Language::C }) { + AndroidToolChainInformation ati; + ati.language = lang; + ati.version = fileName.mid(idx + 1); + QString platform = fileName.left(idx); + ati.abi = AndroidConfig::abiForToolChainPrefix(platform); + if (ati.abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported + continue; + ati.compilerCommand = AndroidConfigurations::currentConfig().gccPath(ati.abi, lang, ati.version); + result.append(ati); + } } return result; } @@ -353,19 +354,22 @@ bool AndroidToolChainFactory::versionCompareLess(const QList &a, const QLis return false; } -bool AndroidToolChainFactory::versionCompareLess(AndroidToolChain *atc, AndroidToolChain *btc) +bool AndroidToolChainFactory::versionCompareLess(QList atc, + QList btc) { - QList a = versionNumberFromString(atc->ndkToolChainVersion()); - QList b = versionNumberFromString(btc->ndkToolChainVersion()); + const QList a = versionNumberFromString(atc.at(0)->ndkToolChainVersion()); + const QList b = versionNumberFromString(btc.at(0)->ndkToolChainVersion()); return versionCompareLess(a, b); } -static AndroidToolChain *findToolChain(Utils::FileName &compilerPath, const QList &alreadyKnown) +static AndroidToolChain *findToolChain(Utils::FileName &compilerPath, ToolChain::Language lang, + const QList &alreadyKnown) { return static_cast( - Utils::findOrDefault(alreadyKnown, [compilerPath](ToolChain *tc) { + Utils::findOrDefault(alreadyKnown, [compilerPath, lang](ToolChain *tc) { return tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID + && tc->language() == lang && tc->compilerCommand() == compilerPath; })); } @@ -382,7 +386,7 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath, FileName path = ndkPath; QDirIterator it(path.appendPath(QLatin1String("toolchains")).toString(), QStringList() << QLatin1String("*"), QDir::Dirs); - QHash newestToolChainForArch; + QHash> newestToolChainForArch; while (it.hasNext()) { const QString &fileName = FileName::fromString(it.next()).fileName(); @@ -394,26 +398,30 @@ AndroidToolChainFactory::autodetectToolChainsForNdk(const FileName &ndkPath, Abi abi = AndroidConfig::abiForToolChainPrefix(platform); if (abi.architecture() == Abi::UnknownArchitecture) // e.g. mipsel which is not yet supported continue; - FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, version); + QList toolChainBundle; + for (ToolChain::Language lang : { ToolChain::Language::Cxx, ToolChain::Language::C }) { + FileName compilerPath = AndroidConfigurations::currentConfig().gccPath(abi, lang, version); - AndroidToolChain *tc = findToolChain(compilerPath, alreadyKnown); - if (!tc) { - tc = new AndroidToolChain(abi, version, ToolChain::Language::Cxx, - ToolChain::AutoDetection); - tc->resetToolChain(compilerPath); + AndroidToolChain *tc = findToolChain(compilerPath, lang, alreadyKnown); + if (!tc) { + tc = new AndroidToolChain(abi, version, lang, + ToolChain::AutoDetection); + tc->resetToolChain(compilerPath); + } + result.append(tc); + toolChainBundle.append(tc); } - result.append(tc); auto it = newestToolChainForArch.constFind(abi); if (it == newestToolChainForArch.constEnd()) - newestToolChainForArch.insert(abi, tc); - else if (versionCompareLess(it.value(), tc)) - newestToolChainForArch[abi] = tc; + newestToolChainForArch.insert(abi, toolChainBundle); + else if (versionCompareLess(it.value(), toolChainBundle)) + newestToolChainForArch[abi] = toolChainBundle; } foreach (ToolChain *tc, result) { AndroidToolChain *atc = static_cast(tc); - atc->setSecondaryToolChain(newestToolChainForArch.value(atc->targetAbi()) != atc); + atc->setSecondaryToolChain(!newestToolChainForArch.value(atc->targetAbi()).contains(atc)); } return result; diff --git a/src/plugins/android/androidtoolchain.h b/src/plugins/android/androidtoolchain.h index 5fd58532f2e..fecfe070fcf 100644 --- a/src/plugins/android/androidtoolchain.h +++ b/src/plugins/android/androidtoolchain.h @@ -104,6 +104,7 @@ public: class AndroidToolChainInformation { public: + ProjectExplorer::ToolChain::Language language; Utils::FileName compilerCommand; ProjectExplorer::Abi abi; QString version; @@ -116,7 +117,8 @@ public: static QList versionNumberFromString(const QString &version); static bool versionCompareLess(const QList &a, const QList &b); - static bool versionCompareLess(AndroidToolChain *atc, AndroidToolChain *btc); + static bool versionCompareLess(QList atc, + QList btc); static QList newestToolChainVersionForArch(const ProjectExplorer::Abi &abi); private: static QHash > m_newestVersionForAbi; From 4f374d4bbfef74515b2689b817b55d8599047b5c Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Wed, 26 Oct 2016 14:40:21 +0200 Subject: [PATCH 04/47] Android: Clean up Kit updates Change-Id: Iab45062012fb91a8f62ee227af8b6a7ab94a8fed Reviewed-by: BogDan Vatra --- src/plugins/android/androidconfigurations.cpp | 82 +++++++------------ 1 file changed, 28 insertions(+), 54 deletions(-) diff --git a/src/plugins/android/androidconfigurations.cpp b/src/plugins/android/androidconfigurations.cpp index e68f0f3473e..33286ccd3d0 100644 --- a/src/plugins/android/androidconfigurations.cpp +++ b/src/plugins/android/androidconfigurations.cpp @@ -1254,16 +1254,13 @@ void AndroidConfigurations::removeOldToolChains() void AndroidConfigurations::updateAutomaticKitList() { - QList existingKits; - foreach (Kit *k, KitManager::kits()) { - if (DeviceTypeKitInformation::deviceTypeId(k) != Core::Id(Constants::ANDROID_DEVICE_TYPE)) - continue; - if (!k->isAutoDetected()) - continue; - if (k->isSdkProvided()) - continue; + const QList existingKits = Utils::filtered(KitManager::kits(), [](const Kit *k) { + return k->isAutoDetected() && !k->isSdkProvided() + && DeviceTypeKitInformation::deviceTypeId(k) == Core::Id(Constants::ANDROID_DEVICE_TYPE); + }); - // Update code for 3.0 beta, which shipped with a bug for the debugger settings + // Update code for 3.0 beta, which shipped with a bug for the debugger settings + for (Kit *k : existingKits) { ToolChain *tc = ToolChainKitInformation::toolChain(k, ToolChain::Language::Cxx); if (tc && Debugger::DebuggerKitInformation::runnable(k).executable != tc->suggestedDebugger().toString()) { Debugger::DebuggerItem debugger; @@ -1276,14 +1273,15 @@ void AndroidConfigurations::updateAutomaticKitList() QVariant id = Debugger::DebuggerItemManager::registerDebugger(debugger); Debugger::DebuggerKitInformation::setDebugger(k, id); } - existingKits << k; } - QHash > qtVersionsForArch; - foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::unsortedVersions()) { - if (qtVersion->type() != QLatin1String(Constants::ANDROIDQT)) - continue; - QList qtAbis = qtVersion->qtAbis(); + QHash > qtVersionsForArch; + const QList qtVersions + = Utils::filtered(QtSupport::QtVersionManager::unsortedVersions(), [](const QtSupport::BaseQtVersion *v) { + return v->type() == Constants::ANDROIDQT; + }); + for (const QtSupport::BaseQtVersion *qtVersion : qtVersions) { + const QList qtAbis = qtVersion->qtAbis(); if (qtAbis.empty()) continue; qtVersionsForArch[qtAbis.first()].append(qtVersion); @@ -1293,7 +1291,7 @@ void AndroidConfigurations::updateAutomaticKitList() IDevice::ConstPtr device = dm->find(Core::Id(Constants::ANDROID_DEVICE_ID)); if (device.isNull()) { // no device, means no sdk path - foreach (Kit *k, existingKits) + for (Kit *k : existingKits) KitManager::deregisterKit(k); return; } @@ -1316,10 +1314,10 @@ void AndroidConfigurations::updateAutomaticKitList() [tc](AndroidToolChain *otherTc) { return tc->targetAbi() == otherTc->targetAbi(); }); - QList qtVersions = qtVersionsForArch.value(tc->targetAbi()); - foreach (QtSupport::BaseQtVersion *qt, qtVersions) { + for (const QtSupport::BaseQtVersion *qt : qtVersionsForArch.value(tc->targetAbi())) { Kit *newKit = new Kit; newKit->setAutoDetected(true); + newKit->setAutoDetectionSource("AndroidConfiguration"); DeviceTypeKitInformation::setDeviceTypeId(newKit, Core::Id(Constants::ANDROID_DEVICE_TYPE)); for (AndroidToolChain *tc : allLanguages) ToolChainKitInformation::setToolChain(newKit, tc); @@ -1338,49 +1336,25 @@ void AndroidConfigurations::updateAutomaticKitList() AndroidGdbServerKitInformation::setGdbSever(newKit, tc->suggestedGdbServer()); newKit->makeSticky(); + newKit->setUnexpandedDisplayName(tr("Android for %1 (GCC %2, Qt %3)") + .arg(static_cast(qt)->targetArch()) + .arg(tc->ndkToolChainVersion()) + .arg(qt->qtVersionString())); newKits << newKit; } } - for (int i = existingKits.count() - 1; i >= 0; --i) { - Kit *existingKit = existingKits.at(i); - for (int j = 0; j < newKits.count(); ++j) { - Kit *newKit = newKits.at(j); - if (matchKits(existingKit, newKit)) { - // Kit is already registered, nothing to do - newKits.removeAt(j); - existingKits.at(i)->makeSticky(); - existingKits.removeAt(i); - for (ToolChain::Language lang : ToolChain::allLanguages()) - ToolChainKitInformation::setToolChain(existingKit, ToolChainKitInformation::toolChain(newKit, lang)); - KitManager::deleteKit(newKit); - j = newKits.count(); - } - } - } - - foreach (Kit *k, existingKits) { - ToolChain *tc = ToolChainKitInformation::toolChain(k, ToolChain::Language::Cxx); - QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k); - if (tc && tc->typeId() == Constants::ANDROID_TOOLCHAIN_ID - && tc->isValid() - && qtVersion && qtVersion->type() == QLatin1String(Constants::ANDROIDQT)) { - k->makeUnSticky(); - k->setAutoDetected(false); + QSet rediscoveredExistingKits; + for (Kit *newKit : newKits) { + Kit *existingKit = Utils::findOrDefault(existingKits, [newKit](const Kit *k) { return matchKits(newKit, k); }); + if (existingKit) { + existingKit->copyFrom(newKit); + KitManager::deleteKit(newKit); + rediscoveredExistingKits.insert(existingKit); } else { - KitManager::deregisterKit(k); + KitManager::registerKit(newKit); } } - - foreach (Kit *kit, newKits) { - AndroidToolChain *tc = static_cast(ToolChainKitInformation::toolChain(kit, ToolChain::Language::Cxx)); - AndroidQtVersion *qt = static_cast(QtSupport::QtKitInformation::qtVersion(kit)); - kit->setUnexpandedDisplayName(tr("Android for %1 (GCC %2, Qt %3)") - .arg(qt->targetArch()) - .arg(tc->ndkToolChainVersion()) - .arg(qt->qtVersionString())); - KitManager::registerKit(kit); - } } bool AndroidConfigurations::force32bitEmulator() From 51e755d4133b91dded098ba978278859af287476 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Oct 2016 13:44:47 +0200 Subject: [PATCH 05/47] Version bump for after 4.2-beta Change-Id: Ide9a51c899914531e9d23a2adf614d424a2746d8 Reviewed-by: Eike Ziller --- qbs/modules/qtc/qtc.qbs | 4 ++-- qtcreator.pri | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 69d2f6c8762..d2c7cc3bf74 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -5,13 +5,13 @@ import "qtc.js" as HelperFunctions Module { property string ide_version_major: '4' property string ide_version_minor: '1' - property string ide_version_release: '82' + property string ide_version_release: '83' 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: '1' - property string ide_compat_version_release: '82' + property string ide_compat_version_release: '83' 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 1fcae0baf25..aec2268a5fc 100644 --- a/qtcreator.pri +++ b/qtcreator.pri @@ -1,8 +1,8 @@ !isEmpty(QTCREATOR_PRI_INCLUDED):error("qtcreator.pri already included") QTCREATOR_PRI_INCLUDED = 1 -QTCREATOR_VERSION = 4.1.82 -QTCREATOR_COMPAT_VERSION = 4.1.82 +QTCREATOR_VERSION = 4.1.83 +QTCREATOR_COMPAT_VERSION = 4.1.83 VERSION = $$QTCREATOR_VERSION BINARY_ARTIFACTS_BRANCH = master From 3de8b56d88cbf3003fc9ba23b03e39a13fa75c1c Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 27 Oct 2016 14:29:04 +0300 Subject: [PATCH 06/47] Theme: Remove some more unused entries Change-Id: Ie2df7520871db21930c39fd976fa8739d354a2dc Reviewed-by: Alessandro Portale --- src/libs/utils/theme/theme.h | 11 --------- .../qmakeprojectmanager/qmakenodes.cpp | 24 +++++++------------ 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 0b8970423b6..a859871d542 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -149,9 +149,7 @@ public: PaletteShadow, PaletteWindowDisabled, - PaletteBackgroundDisabled, PaletteWindowTextDisabled, - PaletteForegroundDisabled, PaletteBaseDisabled, PaletteAlternateBaseDisabled, PaletteToolTipBaseDisabled, @@ -299,18 +297,9 @@ public: enum Gradient { DetailsWidgetHeaderGradient, - Welcome_Button_GradientNormal, - Welcome_Button_GradientPressed }; enum ImageFile { - ProjectExplorerHeader, - ProjectExplorerSource, - ProjectExplorerForm, - ProjectExplorerResource, - ProjectExplorerQML, - ProjectExplorerOtherFiles, - ProjectFileIcon, IconOverlayCSource, IconOverlayCppHeader, IconOverlayCppSource, diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index e194c73882e..0f588c7a55c 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -87,26 +87,25 @@ using namespace Utils; struct FileTypeDataStorage { FileType type; - Theme::ImageFile themeImage; const char *typeName; const char *icon; const char *addFileFilter; }; static const FileTypeDataStorage fileTypeDataStorage[] = { - { HeaderType, Theme::ProjectExplorerHeader, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Headers"), + { HeaderType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Headers"), ProjectExplorer::Constants::FILEOVERLAY_H, "*.h; *.hh; *.hpp; *.hxx;"}, - { SourceType, Theme::ProjectExplorerSource, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Sources"), + { SourceType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Sources"), ProjectExplorer::Constants::FILEOVERLAY_CPP, "*.c; *.cc; *.cpp; *.cp; *.cxx; *.c++;" }, - { FormType, Theme::ProjectExplorerForm, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Forms"), + { FormType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Forms"), Constants::FILEOVERLAY_UI, "*.ui;" }, - { StateChartType, Theme::ProjectExplorerForm, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "State charts"), + { StateChartType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "State charts"), ProjectExplorer::Constants::FILEOVERLAY_SCXML, "*.scxml;" }, - { ResourceType, Theme::ProjectExplorerResource, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Resources"), + { ResourceType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Resources"), ProjectExplorer::Constants::FILEOVERLAY_QRC, "*.qrc;" }, - { QMLType, Theme::ProjectExplorerQML, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "QML"), + { QMLType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "QML"), ProjectExplorer::Constants::FILEOVERLAY_QML, "*.qml;" }, - { UnknownFileType, Theme::ProjectExplorerOtherFiles, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Other files"), + { UnknownFileType, QT_TRANSLATE_NOOP("QmakeProjectManager::QmakePriFileNode", "Other files"), ProjectExplorer::Constants::FILEOVERLAY_UNKNOWN, "*;" } }; @@ -159,10 +158,7 @@ QmakeNodeStaticData::QmakeNodeStaticData() const QPixmap dirPixmap = qApp->style()->standardIcon(QStyle::SP_DirIcon).pixmap(desiredSize); for (unsigned i = 0 ; i < count; ++i) { - QIcon overlayIcon; - const QString iconFile = creatorTheme()->imageFile(fileTypeDataStorage[i].themeImage, - QString::fromLatin1(fileTypeDataStorage[i].icon)); - overlayIcon = QIcon(iconFile); + const QIcon overlayIcon(QLatin1String(fileTypeDataStorage[i].icon)); QIcon folderIcon; folderIcon.addPixmap(FileIconProvider::overlayIcon(dirPixmap, overlayIcon)); const QString desc = QCoreApplication::translate("QmakeProjectManager::QmakePriFileNode", fileTypeDataStorage[i].typeName); @@ -171,9 +167,7 @@ QmakeNodeStaticData::QmakeNodeStaticData() desc, filter, folderIcon)); } // Project icon - const QString fileName = creatorTheme()->imageFile(Theme::ProjectFileIcon, - QLatin1String(ProjectExplorer::Constants::FILEOVERLAY_QT)); - const QIcon projectBaseIcon(fileName); + const QIcon projectBaseIcon(ProjectExplorer::Constants::FILEOVERLAY_QT); const QPixmap projectPixmap = FileIconProvider::overlayIcon(dirPixmap, projectBaseIcon); projectIcon.addPixmap(projectPixmap); From d8eb2bf762f7c47844a084ef418d4cf16e327a1d Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 27 Oct 2016 12:35:06 +0200 Subject: [PATCH 07/47] QmlDesigner: Fix warning Change-Id: I751ef6b28dd57a98b1989a875d4c367f8bf50ece Reviewed-by: Tobias Hunger Reviewed-by: Tim Jenssen --- src/plugins/qmldesigner/designercore/model/modelnode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp index 2614ca939ca..5b4da5cbd82 100644 --- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp @@ -223,7 +223,7 @@ static bool idContainsWrongLetter(const QString& id) bool ModelNode::isValidId(const QString &id) { - return id.isEmpty() || (!idContainsWrongLetter(id) && !idIsQmlKeyWord(id)) && !isIdToAvoid(id); + return id.isEmpty() || (!idContainsWrongLetter(id) && !idIsQmlKeyWord(id) && !isIdToAvoid(id)); } bool ModelNode::hasId() const From 48537ca197cfea2b901a54d90546ed214bd68497 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 27 Oct 2016 15:06:01 +0200 Subject: [PATCH 08/47] QmlDesigner: Crash fix Editing subcomponents should only be possible for graphical items. Qt Creator was crashing in case the node was something else. Change-Id: Ia0e286c666b0b485da0817678ca2048ace260c9b Reviewed-by: Tim Jenssen --- .../qmldesigner/components/integration/componentview.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/integration/componentview.cpp b/src/plugins/qmldesigner/components/integration/componentview.cpp index 1bd29179ec8..77d2bf78a8a 100644 --- a/src/plugins/qmldesigner/components/integration/componentview.cpp +++ b/src/plugins/qmldesigner/components/integration/componentview.cpp @@ -25,6 +25,9 @@ #include "componentview.h" #include "componentaction.h" + +#include + #include #include @@ -193,7 +196,9 @@ void ComponentView::searchForComponentAndAddToList(const ModelNode &node) foreach (const ModelNode &node, node.allSubModelNodesAndThisNode()) { if (node.nodeSourceType() == ModelNode::NodeWithComponentSource || (node.hasParentProperty() - && !node.parentProperty().isDefaultProperty())) { + && !node.parentProperty().isDefaultProperty() + && node.metaInfo().isValid() + && node.metaInfo().isGraphicalItem())) { if (masterNotAdded) { masterNotAdded = true; addMasterDocument(); From 25b4e9c8cea04c5eef72ffc3b8c7a82f2f7ec846 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Wed, 26 Oct 2016 16:41:22 +0200 Subject: [PATCH 09/47] Doc: Describe code completion in CMake editor Change-Id: Ia8d2a5f6c13f3d1f8372e201ef65d39811589e10 Reviewed-by: Tobias Hunger --- doc/src/editors/creator-editors.qdoc | 3 +++ doc/src/projects/creator-projects-cmake.qdoc | 2 ++ 2 files changed, 5 insertions(+) diff --git a/doc/src/editors/creator-editors.qdoc b/doc/src/editors/creator-editors.qdoc index 3ccaaf3eb88..594956a3e79 100644 --- a/doc/src/editors/creator-editors.qdoc +++ b/doc/src/editors/creator-editors.qdoc @@ -915,6 +915,9 @@ \li C++ code snippets, which specify C++ code constructs + \li CMake code snippets that you can use when editing \c CMakeLists.txt + files in the CMake editor + \li QML code snippets, which specify QML code constructs \li Nim code snippets, which specify Nim code constructs diff --git a/doc/src/projects/creator-projects-cmake.qdoc b/doc/src/projects/creator-projects-cmake.qdoc index 525c10eb389..bf542beb3f5 100644 --- a/doc/src/projects/creator-projects-cmake.qdoc +++ b/doc/src/projects/creator-projects-cmake.qdoc @@ -161,6 +161,8 @@ \li Keyword completion + \li Code completion + \li Auto-indentation \li Matching parentheses and quotes From bacb0a74a0afbd0a93666972d59fd8c42637e3a2 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Wed, 26 Oct 2016 12:49:58 +0200 Subject: [PATCH 10/47] Qt options page: Simplify code a bit Change-Id: I70ea3134550c01f6c81f8a15d2730dc906d834a7 Reviewed-by: Tim Jenssen --- src/plugins/qtsupport/qtoptionspage.cpp | 7 +------ src/plugins/qtsupport/qtoptionspage.h | 1 - 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 97fc03e5fab..f18724a8b56 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -685,11 +685,6 @@ void QtOptionsPageWidget::userChangedCurrentVersion() updateDescriptionLabel(); } -void QtOptionsPageWidget::qtVersionChanged() -{ - updateDescriptionLabel(); -} - void QtOptionsPageWidget::updateDescriptionLabel() { QtVersionItem *item = currentItem(); @@ -736,7 +731,7 @@ void QtOptionsPageWidget::updateWidgets() m_versionUi->formLayout->addRow(m_configurationWidget); m_configurationWidget->setEnabled(!version->isAutodetected()); connect(m_configurationWidget, &QtConfigWidget::changed, - this, &QtOptionsPageWidget::qtVersionChanged); + this, &QtOptionsPageWidget::updateDescriptionLabel); } } else { m_versionUi->nameEdit->clear(); diff --git a/src/plugins/qtsupport/qtoptionspage.h b/src/plugins/qtsupport/qtoptionspage.h index 09363c89bc1..fc7899c9e03 100644 --- a/src/plugins/qtsupport/qtoptionspage.h +++ b/src/plugins/qtsupport/qtoptionspage.h @@ -85,7 +85,6 @@ private: private: void updateQtVersions(const QList &, const QList &, const QList &); - void qtVersionChanged(); void versionChanged(const QModelIndex ¤t, const QModelIndex &previous); void addQtDir(); void removeQtDir(); From 10ddde412581df0a5353691632b347ee6d78c5ed Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 26 Oct 2016 16:41:17 +0200 Subject: [PATCH 11/47] iOS: also process stderr to look for QML debug port This is where the "Waiting for connection ..." message usually appears. In general this mechanism of first replacing the port in the message and then parsing the message to figure out that the iostool (not the application) is actually listening is very confusing and backwards, but fixing this is material for the master branch. Change-Id: I73d3c5a34482403d275e6ea7a9ad59996121b02e Task-number: QTCREATORBUG-17141 Reviewed-by: Christian Stenger --- src/plugins/ios/iosanalyzesupport.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/ios/iosanalyzesupport.cpp b/src/plugins/ios/iosanalyzesupport.cpp index f44e6627b12..7f04ece41c8 100644 --- a/src/plugins/ios/iosanalyzesupport.cpp +++ b/src/plugins/ios/iosanalyzesupport.cpp @@ -102,8 +102,10 @@ void IosAnalyzeSupport::handleRemoteOutput(const QString &output) void IosAnalyzeSupport::handleRemoteErrorOutput(const QString &output) { - if (m_runControl) + if (m_runControl) { m_runControl->appendMessage(output, Utils::StdErrFormat); + m_outputParser.processOutput(output); + } } } // namespace Internal From aa118539a41899f79a804341fd5695222b9fae74 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Wed, 26 Oct 2016 16:32:20 +0200 Subject: [PATCH 12/47] CMake: Fix warnings about cmake configuration model The index was handled wrongly. Change-Id: I8a98c7a16e32798a9b7662c6c5c1683d248580da Reviewed-by: Leena Miettinen Reviewed-by: Tim Jenssen --- src/plugins/cmakeprojectmanager/configmodel.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/plugins/cmakeprojectmanager/configmodel.cpp b/src/plugins/cmakeprojectmanager/configmodel.cpp index 4ef34dd7fab..8516e3bc00b 100644 --- a/src/plugins/cmakeprojectmanager/configmodel.cpp +++ b/src/plugins/cmakeprojectmanager/configmodel.cpp @@ -44,17 +44,12 @@ ConfigModel::ConfigModel(QObject *parent) : QAbstractTableModel(parent) int ConfigModel::rowCount(const QModelIndex &parent) const { - QTC_ASSERT(parent.model() == nullptr || parent.model() == this, return 0); - if (parent.isValid()) - return 0; - return m_configuration.count(); + return parent.isValid() ? 0 : m_configuration.count(); } int ConfigModel::columnCount(const QModelIndex &parent) const { - QTC_ASSERT(!parent.isValid(), return 0); - QTC_ASSERT(parent.model() == nullptr, return 0); - return 3; + return parent.isValid() ? 0 : 3; } Qt::ItemFlags ConfigModel::flags(const QModelIndex &index) const From 7b25da7e22904285fcebf4f6a5c090455fbc6962 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 27 Oct 2016 15:30:42 +0200 Subject: [PATCH 13/47] Doc: Describe new flame graphs in QML Profiler You can now visualize memory consumption and allocations of functions in addition to their time consumption. Change-Id: I1c36019a5e3a161332a956a4b2d4aa833ea781dc Reviewed-by: Ulf Hermann --- doc/images/qml-profiler-flamegraph.png | Bin 23498 -> 23750 bytes doc/src/analyze/qtquick-profiler.qdoc | 18 +++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/images/qml-profiler-flamegraph.png b/doc/images/qml-profiler-flamegraph.png index 23c6558028f9efb236938890d7ba3beb5745b52e..4e6c694385bd487abaa3249d032a67070cec306b 100644 GIT binary patch literal 23750 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 literal 23498 zcmeAS@N?(olHy`uVBq!ia0y~yU_HXXz|_IP%)r2qsl}4^82+V6CNTVe5-I$xQ}%O=);nhA zpE+uul$4GgI+&Q4_&%NOi@f~z7{0i;xOa(CzZ*4wm59Ff5s!?F%*@QJt*u?Lbn*Ql zp5J0(&-nOqa&q$X^BWo(Qc_Yr^=bqK1*N5>ebds4j*hOVs34$tGH?g|KKYHB1WC*RMJ6crV{apm%dc(M19 zd~I!Q3l=PRx=7~s^{YQjmD!mXf7(gB6A`(4^SYax+XrVZK^8_i7N)P>!msS zJ!$FJvRpsn1XX!hy1KgTY;7H7*dN`$|2SLp$5HLy3zc3?6#K3&`ff4rKT{rmPWIm3 z-Z^vTq;hdQHW%gP<^A#F2QM?@+ZGvJ0haqR-1$6Qooamk;v8S=G%rg_M{;pE2(i6* z@gh)}>$8RWn|#qeA)yUoVpWE`4g9?8JtZo6IlnJZ|1w)4N1JD}2&a{$g`vK_5i85= z*|Rqri9B{zJQcuyL5geJ)~)S)T;?LIHA-9w>Rg9~1uhB;@7cAp&sI22isMR{ptQ8~ zCpn(!y4=fk1x}tgaVJjxg00+A0p4sm?(3!^d%Xm&+H#+?)CVo5Q&Lj1g#=cwTzMf<{-vc@ zt-a8R0EN53YUk9{rn!r}j?`FurR-$B>X%^fo@Oq%i+}Ny*GZ#i>b&bu&^6+G1X=Skb;Tt9?~k-JHba z(jfCN<9r5&h(1pj$B>F!Z|2zM|8kQ#zL#ZxQ^kj*$p?=e+GNN$lX2w=j|DoZOs+RI zf~R}LZBjYq#TLi#%KF8m-ig;Im_a*HM%-RB0%7@>%UjA=! zee%0vd-=>(e|6RscD{BE(N3REJe+YhEmL{9WA%#V2EUnRD#kx~Y}NUF;eU;I)rodr zjtEFw$voWc{%>01jb{BxGXgUX%$Xd`#Cy|6%~50a&lJA@0S{Wtj_&-vP|{hGhfQL8 z17DooORo91?55wo!8o0B#`o!|0lkO%=J0Hd(#?Hha^cygX&oWb+nlpJe(yiSkXZfy z`0~B%rd+%;ii1=yOkg%)$TixSt0sPovth>kHvTQF7fO9}c>kYpxopt3;K=8TyVc9K z3yRpi+?Ue#eY0+kRZ+mI+jE`?2?msO23%IryWY0-@TFyco=@xGVdUdG{r8&V?i&|n zw;bNUzIE>n=gVjAoW5exkeMHt{Dkf68<7bnjKy*nE=#d%6dqU4UfQL6_APUBH-l4t z_M<|JZFc#~zi&zKOEF#G&*Aq(OSv#j?&?3~EfXilDzmjrn#Qq*FS#(QHIciMX%<_? zgEh-%zC5=&O--EjZqLSs6+iFtB%EpIO6YP_@%tat_pk48vuXLMV}0{lH_VkkminjR z+~Z(hhglH|58dB)x90b?_w7RKk8L>r{>_%3?*Cj@{|-vFIQw_`l&KF?#5*On9-6dH zjBRd@Vef`pUDFf))agA+X%FB3rK6;^c6aQaTEE0(J?rErhfECHScI;#gjTrcyX;6m z5ZCIpXJhZ-qg&M{xs}*)-Ba&twvA4Z5Bl=ZX?WLDpaCwuk0%l~oevGjaC9i#MNQ?0oz*TG2VVBhEL%OfZL z?KP0uQ_@$xt3a^#$>%L6yB$^5F}Epjzn@Xnvf@bdy>ojS&&Y}Q8)qC$@+qNzCUHmof9aO^vCpeu5cgAk%h9v&C5>`5wEo3F< z?0&hxaK=5$HP>4wY>*bLU9k6wlh3+Ox6`|idaKlHY;6#(YFZJ-|NhyNtS0{D5AGRT zNgA_T&F0>Gd;gakWk&PooQ+^_FzicYQS6T6Pv-E7S!K@owQrVQ;hVMo2K;-XpI?)H zu}j0`!4`cdE_TJ6=fkT+Hh#3*R$D&d*vG;N!m;v7+>9Ml+pguVcF%j4_4#!Flz6k3 zLgB2A-g7z*Z(Z_omWiy@nvc#U)@>Q=WohZvZAXM>&f{fEpXzb$(UH2Dnx1PUTMg40 zdp{bS+xC6Yj%D4oo;$X$Ff0;3C$ZD8_L6GvtY@D}_$M;>7_31-4GOs2IaMTq&_hpUPo4b$y#-6VWm#^g8Dk18)B7<|r>usF97vpC8r0>@M z@r6B6Un$Ak>xHp&($VNU2hZ%Tjj0efD4nl9Eda(zQm%+)zxyO-HIZ&#S4 z{aBzdUaw@nLN>!5*W9)8vxE!lnx$=d=49*)bhc-sE~|cA_xJ1kO{(rI3=`h_N`H2063;3$& z#%y+e-GZ9UH(7+#`6FaakF41Jcw@9VZ__EIwe0^EKS5Z_lKD#+`MLTd+}QZ*GI2c=K3FvSe7rS9_e2-b57UiQd^EY87Cfo<3FRr z!^F#Zq=xrHwiSn~#?m!zM%}MWxU#J#2Rtg>FLZrBTV1fuG%4n9_Y9okvpy`UbUBr~ z;@NhUKHaN(w>We<_j61*QJTJFanqsmdqotUu3@WCdBAr^Y{M@xoquPiA27e~pvq^v z&XVOecd773)^>VBhG^H;)<8A&-}vB^RuOQ^4$1K zbDmt=GD$HjBUrU}X7Clq2S<1ng~A(lJ(zU--FnXb|Lz4%02MoVSGjiXZkztP__UDj z>yLrkTqZHOY>Ty;_EhJuaMjd5D;7WYel#VVx$o2b%RiY~k9<7vmSMHI(#P}m|Nlr& z_z^8%6_f0dRhD+lQ=DnxrBBk9MvC$4mVN*B_e-SV84jbk9jzH{Lh*dkSczUwEUopgm#jG$edK~&15f#@;||(Rn)}=~)$U#T@{Y9P49g8`7QYMs z9CB5{^1*bIV=S}2ICPq`ZvTCubpNtH$0FwZb(5{$9eSqEd;;6NwHk|@x++{%I-5>T z|M5B`^n9FTXS9Dh@6Dac6WM>RSn$C=UGoL239HlOBZbv(>U+YZH&`^jS$3tdFh9d( z;yIQ>XPTnzg>=eZxJI167XG?2)@V_L%cC|GPdA@OH>!-k7HK)Xu`c^B`ReDavez@8 zW$$0Mb@{TNcecN^v#>w;ID7ZUCyh^B&)8j-@|rV0ctc%Vhh=N;#AfB6Qa80$D^A&4 z+&kGe@{+rl*(B#nGj@8En20AUedKePyWpbNpZSH$MT1fg+*^0{j|*G>B8!HwFWbM? zb_z3fCToY=tXH}$JkjiWKX;;o693EXXHPv_GQA_or1S7!lU2R1S%SLqR~){-;>gm4 zBB^>mVkRAR5ENNf!_*#Kdc8E-K*Uv$#d}wq{nssP%P+D=9iE}%`o8H%c>c#lQpdg) zeY7y=`JA*f;vA22ZDhszMU1=pjlYQfHQS<;Hh=wz=nr+mYviWzBxbcg-yyAdl>7Ca z-|~(f&B41m=5)WUXGjgb%wf7w{*w_~lSjYC;t2td?zXqLzw5C0^IdxT;egZw_t=+< zKCHQ+<@BpJ;M9RGxs&J8t^DgXCkTWWWJ-j(mpo+e4!##wdMG3M(Y5Xe%7PA$ESzNW zJUb(bcWf{gSChT=Uenq|DTjG#Tc=9NKk+(#6SvMoX1+a3IieR$dG~s5t7(I!_vJnN z{FXN?`&m2JY4Z7-2PYoT;GI%o%d#!_pIrZI!9_y+Rq}KESgyV<R{f9^4^Uqg*%5N*K^@wLaTH8DCSkHnDr$3e+ z^nI0fZk3ek+d~ss_AfD9)-1HV;n3{DNp&o-d*g(Tm((r1s_^&c+L-6!>pma<#{0A4 zsAOc%5nY#s^ScDAqE{wAdsedV9qaw&$#4AItk3?{JbJzG)O{gFgH0NDQhv-THEUmX z+NA86etnAZy@MUorS*1s3UuzaI~!B-HO=qU@#Q-{{||op|He+we{1e)IBQQ0zWLOD zN?p#AigW*8Sk2$56MbV+i9>w4*v&tz-}2&_kAE^5?)KzO+&=Gr>h-?L%WQ`X`Zgcf zyr;NbM_0CEk&CZ$*Di&~q9ra>tz{bfekW?40)p<+4{S zWI68O`S`_8%Zca3=WbeH|EyqMKzXv&nF($&_cK3b*HvYGyR>oMuSL4|dG8%L-gG^` zPUhq4bknUrcQ34spH+QZp3!d4zBkWaUzOS$XMFeO!F$g#_x+rnpkTE+IaiNA$TCySTV~zSOZ;L84Ge$!$)@i@OO&Iy<;}1l5(a4BX~) ztT=G3bBD*T-O-zD4tEF(?v*GM+<31ua?LkCWxarx`}5};K5}uH?Iv?^E$`x|9jjyA zWDI&0mHk|{6dq};wqz=>-EvP?fs>(D@c)4qbARl}e)}|e--6v)8NVC8xHFkJ{XWQG z&tF?D;g~eTSIt>?N&5EpzkmB(XPO(>EvT+kW%x){lF@uq`l=$^)n5va|D80;&1Op1 z?%(tDAN8i4e8U{n-%z(ZWnT?z+y1#LWtWs*^JF|zX>J>SdvDz4RoNdOgjcBhxvXCq zq$zqhUa(wA-JB7sa5oDc_>hRnx3rrc|&^agMFF zmMXSx?bu}as7hVVLurOv&7E(m%LMmtQ%Ypr$>R5Y>spltKWoXCPre-bI{V|#%wF!2 z+=?@{g-TV7%Jam2$MiJ>D7^@&`T5{X&5?&zypoFI>(>Z=ukvUWXLA!%zs#Nd{N0h# zT>U-iM>;j6mDl+%-|{3mMNW?~-iyJlC_U@5puNoQjqkRlSkHf#eLU)|ari&BAEMz_ zQ-0K#nQJy=^Ira(xkvrpx^ruL_Y}L$=`b>Uq?FXI&bIM9bM|_9~F zvuDq(5iDQ6_@uDf#%ba_+8?X*Iii`qtbMVhj7eBb^%D%5e-m z7J_RJb%--4|7+iC9agB+^~hk}u{qDSMCAzQE?TsK%S%U$NmwAItE6v9^qQQO%p9J} z>k8g8pAnYGS>|o%IxjI={|k_}aX7QLf5*EM znJZnUq((Qc3aFJAXv{d{I}rv2By zg0*imcEu-0>$pzqex~v{@%^>B*=GPX+sZT}zaVPIg!{C<}gkwruZ(>rwgsaeH=cxOUAeBKdS| zsj@R$_Lq2b@({_EbwfMP)`@7!3bJ3wWmBHFYP!Q_fx_i~ouV#3TdubE zZc#r}=kM7+vZlR=>iD6)eAd_ZQiUhypWWHXyy0NN5&4(mH&1Q(^z*);c>T|??8wJ6 zEgF6wOgPf5vhou<^TeqAPY>@`{+IML+-l!#hGD$bbz5*aQY)1&&e}S zY8{{zd4I;#H4R*oqzDqvHr*J z)E-;uZ7yn`AzN9uVWy0VrhK2`NqI#V8zvW-1NNJ)cP)JCBE!)3ZJ%JF;v9DgI{z0PX;j+(gV zN7a@15<~>czs9~${v5Eoi~rcIHo^GXm-C#S?3J6bb04qEonFV3&sNq3mntpI)BXin zRm=YkmY<>h`$EiG*H`bKewxz3Ea7@2wl+BSR8X+~v8WcMyi?C!+WDIbF3x;lb@c3} zmzP(~dh5MhE2P^i>iw(gdzx8Ga^}Y@iPPEX$M}KW<<8NYS(;0uzF(5g{;d4Ye&@EL z%+~vz<>_j3yOWdq^p||x`cL8S%}f6(zw3CLyT}~SP?D=qf7iRU*LBYYuQ?y){y1*; z=-r8#j5ghjkD4s*~jPZE7#3<_If?UO^ix>3N0P(4IRuJijM>p9x*s|RIqedGzcik z5tMrG5PD1ilq3uut@?fGhP>|QY23MoIk(j@^mQ=LSf`;pPhH7#-LLESn)%glNV&)y z_~I)0@mEO7{;;>puhmJWXFqxUJ6dN;tJ;kanYVU#-mMobWDpigJre%Y=w$dR`{md6 z6mDZKUhz_lJ9i=Hw!|a5|C%cCB{(hW*>O_N{#=j!)@%KnLxbLJxbVz>1FO=$h@!bn z2|39n2m#D_!m!-~FK?>B!y}&u)G?_0;ZJpLrpJr?FI_>7i?KQx*oS&gOl; z{j}@fHGWSQUYK7%UjRI{W(4@0UM(`8l<8`S128 zjd4f1UG2W=&P+eOT1&s%P>_9s*=E7%f@ZaIFRfj7^16|TqF~taz`f1dA4@BD&rXlN z{#EVtEq^6Gg~T*vJ^L5-Ic2M}@0w2*sCAzIsv~=T_u8i!VttJf8a z9@oEl&}R1O#dmsy3mG_z-|Ieq_PJ8}qx@yT>#MWt|Ihuj*8l0_wJ-Mf=Z83rw> z=A)6HS;`+V2&Ef<+Z)c{=EMO3a1+Cz1>Ef5fiy)>rJgKO&O64z@UQ%&pgbc(hXuo* zO~LFY3=9k$&A+yr9hYr+(0YXNkP4rGT494hCv%IZjDpW2hD0HDj>#4dGl-Wu<|li_ zfy2d7U~g^i>XfNHHZBt%x-c=Vc(ONodqb0fAUlU}VFPK@?Ad!=WE4{F$^8BwaluvQ zL1vw~@&C77Kcc*kFxvSYVLap_qu@g=%CGFz4YouEwnZ7wC(dYTofMcLd!ti{msQA7 zUH2%&+!{;h>9*!i)}P7U9B%1SLKJpCgP-ofZxtZ;>at;n$OmcU|Xre0}!% z^UXFs`&Ie#)Nk(W*c`5VI%w;<*Xug&zi;oC{ueO4f7QC#x{tQserPRT=py4XhtXw@ zr^}o&>XUzt&Xawt#^Vww@-}8O-?u5cmFb$B7Q65;X|ozEI#BmsrZLsKEV(we_t+7^ z!dV>_g)Vc{l>B4_mv?puyC2C^dNeqN=cGQKI@{jv&WE}p5sH0?;D0%Rn)a&=r7s3V8zq{CUcbs?qvrlke+_`m(+l8K6 zfJFS=YO-rC$%Iuuk~yMZ{k{LPn*eLVp6aV2?=l`R6?b1*r=c8kA?LBtl@4hh-rl3C zK~DvCHgT)uC-zOeJNJ2_V|I4>8jgD({))Vx-{H}sBft1$ReQ(v){gWE7Rigg81$aC zZtQscTKQ3_;-g4Gdqsn}Owt_{u^knTN4{roFR-dLlAB$v#K)|rystjS?%nRa)z-?7 z%mh9*b*wM{7}bBNry@axk9(QYzU*&__m6N}&lM~b25FA{|LCTsL6+8|+0*krZ;IUE zXQli|P2l67j@^FpA3xkOS^sc@`XhrRtw*o7-QJQdJNJd8pm}4*^!_8;zvou(w|&!T z(KDm#hf&Gw4Oco|L*(3S{CeMCYqu3_7d-C%sMjs#e8&z>mpwL*P7Ane7y2JbJkn|T z@!_E~zdK?|=R9QYpErE9Ef>o|oqd@CXU&n0c zBi+jHs+{);`ycuE)lg_Xx1fIi4~u(^FGV5@MGMVyBs!yAj%-$zi(5bY?T;dU!zXvt z`5@7dcH}GXtd~Xn-0LON137Lu9C__@#8`PBN$q z>|x&;HIL6zzb8~UxufEzN6nZ2vwW5x=v&!wKi_$Gp_RmSal!449rMlA?RGtp>^$7I zvg3W7{&jtqJ1RPt zk^(s*9Ko*X2)ixMWcQ(6Jb!mPr^_BampvZ>x7gWsmkG=eZWjd$qy%P2l4$fsd1R2Or8vl|L^vdqXQI48_-NeEC@K=p0kCL{^Zs z=X-X@i{9aP|JdNFm;e!(=lAjQ`)`T8z7k+}RNl7TH}kvT{N!`&lPB@G{Mqcm*1JQX zP{jKG??}7jKkp|O+gE(@p77Q31$%#-y65sI`Aeh!UcGqvj>i&xetVa0kCl@4x}6sP z+>hi}DTRlJEAjL5EB!s#Z>}``^Vj-cCKIhE-Y!=9S8QPXXu7-7y;`-;%KM_$7Ae&g z1`2$fy^yh7^HKTVhhED6%(Wlww-U0?pZLT7#~+XxiCt++g7!A_Q%8(%ZobaTsu2ObE1x4Lq>*<$`qwkt|?3xmv^2Jj8VAA(&?=; z@9ZW{>j;UUGs^$hPgwqhVg9^%ISzYl1(wT;bTnHuT4?eeah&5YM}+;6f}et47jvP2 zx`6u8MvD&Nj>(T4WR7qi@hnu}d&Kf+iG=`rAyZ+H3`E;cl13Y>T<^HXXC?{Ia|$cC>8M{H>?O{@F`!|HuEa#LDY(>eSv` zR=?zbv}ygsUH>CQ`v3ZWw$zSuoU==m|50V^ugK|p<08$Ar{~Z9zeoK2Lf@Ks%N|dE z`Q@YJ5yu$cc=L~uJ7cD8Ud;LE%GwBl`{uVQj@&&rXP5lEQFbIe(`qY3CQn#kxyP<5Vf&gW!SDMWWR842s^&Kll!Wda@hrUG z{o~sfdRv!E;*QNJnG?9f z#Z>(_vc?7leiXRulPtd5bwUNpY1b}M-bD+RIEd&3sYppF&pY6?WY4K{GACx7?lZjc zhAsWP{EV5+vi?SKwZHFAe$4pwfK!L^kwA{ZE6m)AeFE-^M*{hES}dGoS_Rx~HwZl9 zC=_v$`Fh|N`;q;w-yQZ`yr8~XQO_jpn4!S)T~D`X-Fo)m7uQ1h-43g^iz(W^Zk8?3>do)_t{9S8VpfD4n|B%f-6a zCN0}1dEM#JRx$2Sd z>GgTp8!IX+BX#~g_$BWcvpe#`wv`HbO#+WJKu%Zu=dXAq@W1j|`A2T=#qHHvc33`{ z!F}Xf|(tHKtGSMIMF74l;2!Y*4C7S9l!&wZr* zM?uLWj>0Sa*WW1et=M-#>aum==KZx6>idq(v2c?4y4ke4V||sOU8$eUxqII>7Cnl| z2CMhK_C}GfFZ!<3<>yDv{`>Z@=u!3>KgW*6bvx4dKYGi>@Tr~c{LWkxcUAN7njccd zAS?Q>y;01YBmCg5Vb8MWAEiz9Nu^w1N2OQlV}&epfXk)ayXe z_21*a(vg#&@=ngN@MtYaepS+?Qej+EqJA%2-A~|AvVxq!B0*o>OPm}|GNqCC`93~K zkY#Gv(i8Gx+G756Pla8aj~1L*92Rph;L#n42S-lw*58=2BCPn%9O)z1&)(GX2)y2@ zeB^zLMfVoF4q?5Eibn!3XH|97Us%BNf<0lUXl&V|x(fayjaTx7B&TXK-h0){shGE} ziq(I{MR~L9hkGonKCV>o+fvuDSlFHSO1bkL@5;$l-iK5dvt458n|uC^a*v%xy#?R2 zC6(Vk&AsV)Qod??X2F(7!wa47H?!U5T*~>}OpwteT|G`l=i9bT;j_;gn=0H8(EHbM zUcFZC%@N_*zgqV1@~_l>7QOYkvHtR4ExYH2o0RRgD05f|-2XV;ZqnCTOM2FnD=vN5 z$NosL@S{hrTz}D{N8A5g+45^CgUp2w*PpMg5T4>U$F<7M$TrEUevzpApGgsl!TCuo zJER`9c~%`wAZ@@%6P5#7o_gDI$il@%fB??9i=tBs`}0@vqc3MWY?L`I&)v0p;c%z?^BvJW-#)2*h!&Xsv7qB}!gO_+>+iCj z{?hHJUbam3ZVdm_tD2sxmW$at&)t)@O#Zc1{K7ljrINxe75&2Nr|-V3d?Zl$%Uyx( zWqWQ$HayL9c~Icz%@O3Wxuz=q`fGPD$3I0og_oDgK05GHV_|i_^VGs=;y!PW?ELsN z_t-ph&ro*WBXcu08{W7ec~t3=-t(e_OlUxtI^?|TK%$zab4i?&f?H1%a1))n&|lU z$mWMvHFeeXm@V&r_0I{LGQa)Q?0OVIj+R z?BibEvTbrFqthQg^*#aj-pe+tf?uqZJz6)j+H_5SUflB|tVf$A5@PMGOZ|6GHs^Zu z;PBm3Cl39XBiw&jr^wo}P`_%O#{0+i+>#eKiXL4oe$soc^SYz){Ct;prt1HquH5N+ z?8WwKjs=S^pH1EUr}ug-3-yHsrk}id<9hLWHjj9}82fkq1zs7SMU9l-Yac7&dUhnR zf644uM>siICgxu1^4oayQgNvl*Wx>s{P!8Jo!uOK+=}J#+zQd?Z`md5{4{^09Pble z|HE5+QTp=-8N!Z*av{!&c^$8&s5M`jyZ(OXenY$77n#~G!j|tbmlTPd%k)}pb?`Aq znL6)zUV{2xkGx$_p~)%mQEkQRBg#TASv#Z7Nr!PL*2zAKnAyP`E>E~HbNk(!&u4tO(mDS|lx|b`x0!1{B!6FF`P!`GxygGM zVXwX2iP;HX?#|17D)HUXrgM?SMByzNb|22!Np|Zw+UOLU|It_2x6b;GHLGIZub;F2 zvPH0MklJ_7w#49#)0_z<#qvk`CpczK;EgwuC`y-i>N}>|vAjoZcc+4$ec1XNwPA5b zV|fH0t&m@T)A>)A@cb(K!p*Pu-JbruG+q8e)Z0VXjhsL+`Zwn;L*e~sKjrh`abfpw zE-!rW|5e?iyKC25{h0UToE@X`*8|`48h*IS|LYcYSGQ9N{H*4WB=RI4B@3AG_ z?pqq=@-uhQtLA$7WY+w-viqmpep=eWy!`6yPXGP$cd%@Ib5`v1+3eCsPqdEM&s5#4 z{${bgz?vj)EJ?)dL{dpJ{3u+Q>i zrs6!cDE=dNFVtwp2|il!($w}yEMvm@gZiG56RU;i*;K!ux<4;MLp7#cQh)8;b5YCQ z35o2uuE@8bO_#NI!rQ-XciIkh3g2HgHGlJ?b<(QcJKwkzMW-IscbroY+h}3Q&mqop z_d!~R{7~- zgr!X@=-3_k?ANY3jx(W?6ppNSn3MPVtF4H>f8wH}b6&dMaXHkP&QW+pqV~OB+l2;? zeN(E1iyZIY+puA>-$oZd8;-+P# r&O4VTu-}(e-*?NV`|>WyM+})t<$5gq|GGun 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 diff --git a/doc/src/analyze/qtquick-profiler.qdoc b/doc/src/analyze/qtquick-profiler.qdoc index 141ca00fcb0..e482dac5580 100644 --- a/doc/src/analyze/qtquick-profiler.qdoc +++ b/doc/src/analyze/qtquick-profiler.qdoc @@ -557,14 +557,26 @@ \section2 Visualizing Statistics as Flame Graphs The \uicontrol {Flame Graph} view shows a more concise statistical overview - of QML and JavaScript execution. The horizontal bars show the amount of + of QML and JavaScript execution. In the \uicontrol {Visualize Total Time} + view, the horizontal bars show the amount of time all invocations of a certain function took together, relative to the total runtime of all JavaScript and QML events. The nesting shows which - functions were called by which other ones. Mind that, unlike the + functions were called by which other ones. + + \image qml-profiler-flamegraph.png "Flame Graph View" + + To view the total amount of memory allocated by the functions in the + \uicontrol {Visualize Memory} view, select \uicontrol Memory in the + drop-down menu (1). + + To view the the number of memory allocations performed by the functions in + the \uicontrol {Visualize Allocations} view, select \uicontrol Allocations + in the drop-down menu. + + Unlike the \uicontrol Timeline view, the \uicontrol {Flame Graph} view does not show the time spans when no QML or JavaScript is running at all. Thus, it is not suitable for analyzing per frame execution times. However, it is very easy to see the total impact of the various QML and JavaScript events there. - \image qml-profiler-flamegraph.png "Flame Graph View" */ From a6427453f46f978bf4d59a6a22c441baf8482a6c Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Thu, 27 Oct 2016 10:54:54 +0300 Subject: [PATCH 14/47] Fix icons that moved from core to utils Change-Id: Id3151b1cce2d97b2bfb6debaf3cebe53cd6d88ed Reviewed-by: Alessandro Portale --- share/qtcreator/themes/dark.creatortheme | 4 ++-- src/libs/ssh/sftpfilesystemmodel.cpp | 6 +++--- src/plugins/coreplugin/manhattanstyle.cpp | 5 ++--- src/plugins/coreplugin/systemsettings.ui | 6 +++--- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/share/qtcreator/themes/dark.creatortheme b/share/qtcreator/themes/dark.creatortheme index ff8a66cf1c3..b75b3e6ea69 100644 --- a/share/qtcreator/themes/dark.creatortheme +++ b/share/qtcreator/themes/dark.creatortheme @@ -242,5 +242,5 @@ IconOverlayCppSource=:/cppeditor/images/dark_qt_cpp.png IconOverlayPrf=:/qtsupport/images/dark_qt_project.png IconOverlayPri=:/qtsupport/images/dark_qt_project.png IconOverlayPro=:/qtsupport/images/dark_qt_project.png -StandardPixmapFileIcon=:/core/images/dark_fileicon.png -StandardPixmapDirIcon=:/core/images/dark_foldericon.png +StandardPixmapFileIcon=:/utils/images/dark_fileicon.png +StandardPixmapDirIcon=:/utils/images/dark_foldericon.png diff --git a/src/libs/ssh/sftpfilesystemmodel.cpp b/src/libs/ssh/sftpfilesystemmodel.cpp index 922ca57b54e..d3432c5528e 100644 --- a/src/libs/ssh/sftpfilesystemmodel.cpp +++ b/src/libs/ssh/sftpfilesystemmodel.cpp @@ -166,11 +166,11 @@ QVariant SftpFileSystemModel::data(const QModelIndex &index, int role) const switch (node->fileInfo.type) { case FileTypeRegular: case FileTypeOther: - return QIcon(QLatin1String(":/core/images/unknownfile.png")); + return QIcon(":/utils/images/unknownfile.png"); case FileTypeDirectory: - return QIcon(QLatin1String(":/core/images/dir.png")); + return QIcon(":/utils/images/dir.png"); case FileTypeUnknown: - return QIcon(QLatin1String(":/core/images/help.png")); // Shows a question mark. + return QIcon(":/utils/images/help.png"); // Shows a question mark. } } if (index.column() == 1) { diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp index 94ea044f3eb..63bdabb73ce 100644 --- a/src/plugins/coreplugin/manhattanstyle.cpp +++ b/src/plugins/coreplugin/manhattanstyle.cpp @@ -340,9 +340,8 @@ QIcon ManhattanStyle::standardIcon(StandardPixmap standardIcon, const QStyleOpti if (standardIcon == QStyle::SP_ComputerIcon) { // Ubuntu has in some versions a 16x16 icon, see QTCREATORBUG-12832 const QList &sizes = icon.availableSizes(); - if (Utils::allOf(sizes, [](const QSize &size) { return size.width() < 32;})) { - icon = QIcon(QLatin1String(":/core/images/Desktop.png")); - } + if (Utils::allOf(sizes, [](const QSize &size) { return size.width() < 32;})) + icon = QIcon(":/utils/images/Desktop.png"); } return icon; } diff --git a/src/plugins/coreplugin/systemsettings.ui b/src/plugins/coreplugin/systemsettings.ui index 0afda779ea0..b2928f9d47c 100644 --- a/src/plugins/coreplugin/systemsettings.ui +++ b/src/plugins/coreplugin/systemsettings.ui @@ -23,8 +23,8 @@ ? - - :/core/images/help.png:/core/images/help.png + + :/utils/images/help.png:/utils/images/help.png @@ -390,7 +390,7 @@ bigFilesLimitSpinBox - + From bd2653fbaa637ad6e6684f150f50c8e3bb651390 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 25 Oct 2016 15:32:13 +0200 Subject: [PATCH 15/47] Debugger: Introduce and use type ids instead of type in dumpers Change-Id: I569d13d4f5d66cf1606b2b5d047b415659de539b Reviewed-by: Christian Stenger --- share/qtcreator/debugger/boosttypes.py | 12 +- share/qtcreator/debugger/dumper.py | 676 ++++++++++++++++-------- share/qtcreator/debugger/gdbbridge.py | 283 ++++++---- share/qtcreator/debugger/lldbbridge.py | 695 ++++++++++++++++--------- share/qtcreator/debugger/misctypes.py | 2 +- share/qtcreator/debugger/qttypes.py | 27 +- share/qtcreator/debugger/stdtypes.py | 53 +- tests/auto/debugger/tst_dumpers.cpp | 68 ++- 8 files changed, 1163 insertions(+), 653 deletions(-) diff --git a/share/qtcreator/debugger/boosttypes.py b/share/qtcreator/debugger/boosttypes.py index af64c6df7fc..938a0a29670 100644 --- a/share/qtcreator/debugger/boosttypes.py +++ b/share/qtcreator/debugger/boosttypes.py @@ -117,25 +117,25 @@ def qdump__boost__unordered__unordered_set(d, value): innerType = value.type[0] bucketCount = d.extractInt(base + ptrSize) #warn("A BUCKET COUNT: %s" % bucketCount) - #warn("X BUCKET COUNT: %s" % d.parseAndEvaluate("s1.table_.bucket_count_")) + #warn("X BUCKET COUNT: %s" % d.parseAndEvaluate("s1.table_.bucket_count_").value()) try: # boost 1.58 table = value["table_"] bucketsAddr = table["buckets_"].integer() #warn("A BUCKETS: 0x%x" % bucketsAddr) - #warn("X BUCKETS: %s" % d.parseAndEvaluate("s1.table_.buckets_")) + #warn("X BUCKETS: 0x%x" % d.parseAndEvaluate("s1.table_.buckets_").pointer()) lastBucketAddr = bucketsAddr + bucketCount * ptrSize #warn("A LAST BUCKET: 0x%x" % lastBucketAddr) - #warn("X LAST BUCKET: %s" % d.parseAndEvaluate("s1.table_.get_bucket(s1.table_.bucket_count_)")) + #warn("X LAST BUCKET: 0x%x" % d.parseAndEvaluate("s1.table_.get_bucket(s1.table_.bucket_count_)").pointer()) previousStartAddr = lastBucketAddr #warn("A PREVIOUS START: 0x%x" % previousStartAddr) - #warn("X PREVIOUS START: %s" % d.parseAndEvaluate("s1.table_.get_previous_start()")) + #warn("X PREVIOUS START: 0x%x" % d.parseAndEvaluate("s1.table_.get_previous_start()").pointer()) item = d.extractPointer(previousStartAddr) #warn("A KEY ADDR: 0x%x" % item) - #warn("X KEY ADDR: %s" % d.parseAndEvaluate("s1.table_.get_previous_start()->next_")) + #warn("X KEY ADDR: 0x%x" % d.parseAndEvaluate("s1.table_.get_previous_start()->next_").pointer()) item = d.extractPointer(previousStartAddr) #warn("A VALUE: %x" % d.extractInt(item + ptrSize)) - #warn("X VALUE: %s" % d.parseAndEvaluate("*(int*)(s1.table_.get_previous_start()->next_ + 1)")) + #warn("X VALUE: %x" % d.parseAndEvaluate("*(int*)(s1.table_.get_previous_start()->next_ + 1)").integer()) with Children(d, size, maxNumChild=10000): for j in d.childRange(): d.putSubItem(j, d.createValue(item + 2 * ptrSize, innerType)) diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index c0264a1fdb3..79026875ee2 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -217,13 +217,16 @@ class PairedChildrenData: self.pairType = pairType self.keyType = keyType self.valueType = valueType - self.isCompact = d.isMapCompact(self.keyType, self.valueType) - self.childType = valueType if self.isCompact else pairType class PairedChildren(Children): def __init__(self, d, numChild, useKeyAndValue = False, pairType = None, keyType = None, valueType = None, maxNumChild = None): self.d = d + if pairType is not None: + try: + pairType = pairType.stripTypedefs() + except: + pass if keyType is None: keyType = pairType[0].unqualified() if valueType is None: @@ -233,7 +236,6 @@ class PairedChildren(Children): d.pairData.vname = 'value' if useKeyAndValue else 'second' Children.__init__(self, d, numChild, - d.pairData.childType, maxNumChild = maxNumChild, addrBase = None, addrStep = None) @@ -286,6 +288,8 @@ class DumperBase: self.qtNamespaceToReport = None self.passExceptions = False + self.typeData = {} + self.resetCaches() self.resetStats() @@ -416,7 +420,6 @@ class DumperBase: self.currentValue = ReportItem(); self.currentType = ReportItem(); - def exitSubItem(self, item, exType, exValue, exTraceBack): #warn('CURRENT VALUE: %s: %s %s' % # (self.currentIName, self.currentValue, self.currentType)) @@ -510,6 +513,71 @@ class DumperBase: self.ptrSize = lambda: result return result + def lookupType(self, typeName): + nativeType = self.lookupNativeType(typeName) + return None if nativeType is None else self.fromNativeType(nativeType) + + def listTemplateParameters(self, typename): + targs = [] + if not typename.endswith('>'): + return targs + + def push(inner): + # Handle local struct definitions like QList + inner = inner.strip()[::-1] + p = inner.find(')::') + if p > -1: + inner = inner[p+3:].strip() + if inner.startswith('const '): + inner = inner[6:].strip() + if inner.endswith(' const'): + inner = inner[:-6].strip() + #warn("FOUND: %s" % inner) + targs.append(inner) + + #warn("SPLITTING %s" % typename) + level = 0 + inner = '' + for c in typename[::-1]: # Reversed... + #warn("C: %s" % c) + if c == '>': + if level > 0: + inner += c + level += 1 + elif c == '<': + level -= 1 + if level > 0: + inner += c + else: + push(inner) + inner = '' + elif c == ',': + #warn('c: %s level: %s' % (c, level)) + if level == 1: + push(inner) + inner = '' + else: + inner += c + else: + inner += c + + #warn("TARGS: %s %s" % (typename, targs)) + res = [] + for item in targs[::-1]: + c = ord(item[0]) + if c == '-' or (c >= 48 and c < 58): + if item.find('.') > -1: + res.append(float(item)) + else: + val = toInteger(item) + if val > 0x80000000: + val -= 0x100000000 + res.append(val) + else: + res.append(self.Type(self, item)) + #warn("RES: %s %s" % (typename, [(None if t is None else t.name) for t in res])) + return res + # Hex decoding operating on str, return str. def hexdecode(self, s): if sys.version_info[0] == 2: @@ -822,11 +890,6 @@ class DumperBase: self.putField('sortgroup', sortorder) self.putPlainChildren(value) - def isMapCompact(self, keyType, valueType): - if self.currentItemFormat() == CompactMapFormat: - return True - return keyType.isSimpleType() and valueType.isSimpleType() - def check(self, exp): if not exp: error('Check failed: %s' % exp) @@ -846,8 +909,7 @@ class DumperBase: self.checkIntType(maximum) code = (None, 'b', 'H', None, 'I')[tsize] - #blob = self.readRawMemory(base, maximum) - + #blob = self.readRawMemory(base, 1) blob = bytes() while maximum > 1: try: @@ -1064,7 +1126,7 @@ class DumperBase: itemCount = '100' arrayByteSize = int(itemCount) * innerType.size(); - n = int(arrayByteSize / innerType.size()) + n = arrayByteSize // innerType.size() p = value.address() if displayFormat != RawFormat and p: if innerType.name in ('char', 'wchar_t'): @@ -1212,8 +1274,9 @@ class DumperBase: return False def putFormattedPointer(self, value): + #warn("PUT FORMATTED: %s" % value) pointer = value.pointer() - #warn('POINTER: %s' % pointer) + #warn('POINTER: 0x%x' % pointer) if pointer == 0: #warn('NULL POINTER') self.putType(value.type) @@ -1223,8 +1286,7 @@ class DumperBase: typeName = value.type.name - self.putAddress(pointer) - self.putOriginalAddress(value) + self.putAddress(value.address()) try: self.readRawMemory(pointer, 1) @@ -1238,7 +1300,7 @@ class DumperBase: return displayFormat = self.currentItemFormat(value.type.name) - innerType = value.type.target().unqualified() + innerType = value.type.target() #.unqualified() if innerType.name == 'void': #warn('VOID POINTER: %s' % displayFormat) @@ -1284,19 +1346,21 @@ class DumperBase: #warn('INAME: %s' % self.currentIName) #warn('INNER: %s' % innerType.name) if self.autoDerefPointers or self.currentIName.endswith('.this'): - # Generic pointer type with AutomaticFormat. + derefValue = value.dereference() # Never dereference char types. if innerType.name not in ('char', 'signed char', 'unsigned char', 'wchar_t'): + # Generic pointer type with AutomaticFormat. self.putType(innerType) savedCurrentChildType = self.currentChildType self.currentChildType = innerType.name - self.putItem(value.dereference()) + derefValue.name = '*' + self.putItem(derefValue) self.currentChildType = savedCurrentChildType - self.putOriginalAddress(value) + self.putOriginalAddress(pointer) return #warn('GENERIC PLAIN POINTER: %s' % value.type) - #warn('ADDR PLAIN POINTER: 0x%x' % value.address) + #warn('ADDR PLAIN POINTER: 0x%x' % value.laddress) self.putType(typeName) self.putValue('0x%x' % pointer) self.putNumChild(1) @@ -1305,9 +1369,9 @@ class DumperBase: with SubItem(self, '*'): self.putItem(value.dereference()) - def putOriginalAddress(self, value): - if value.address() is not None: - self.put('origaddr="0x%x",' % value.address()) + def putOriginalAddress(self, address): + if address is not None: + self.put('origaddr="0x%x",' % address) def putQObjectNameValue(self, value): try: @@ -1938,12 +2002,12 @@ class DumperBase: # Should check: innerType == ns::QObjectPrivate::ConnectionList base = self.extractPointer(connections) data, size, alloc = self.vectorDataHelper(base) - connectionType = self.createType('@QObjectPrivate::Connection*') + connectionType = self.createType('@QObjectPrivate::Connection') for i in xrange(size): first = self.extractPointer(data + i * 2 * ptrSize) while first: self.putSubItem('%s' % pp, - self.createValue(first, connectionType)) + self.createPointerValue(first, connectionType)) first = self.extractPointer(first + 3 * ptrSize) # We need to enforce some upper limit. pp += 1 @@ -1974,7 +2038,8 @@ class DumperBase: self.checkIntType(n) addrBase = base innerSize = innerType.size() - #warn('ADDRESS: %s INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType)) + self.putNumChild(n) + #warn('ADDRESS: 0x%x INNERSIZE: %s INNERTYPE: %s' % (addrBase, innerSize, innerType)) enc = innerType.simpleEncoding() if enc: self.put('childtype="%s",' % innerType.name) @@ -2466,7 +2531,7 @@ class DumperBase: return False def putItem(self, value): - #warn('ITEM: %s' % value.stringify()) + #warn('PUT ITEM: %s' % value.stringify()) typeobj = value.type #unqualified() typeName = typeobj.name @@ -2489,8 +2554,9 @@ class DumperBase: return if typeobj.code == TypeCodeTypedef: - strippedType = typeobj.stripTypedefs() - self.putItem(value.cast(strippedType)) + #warn('TYPEDEF VALUE: %s' % value.stringify()) + #strippedType = typeobj.ltarget + self.putItem(value.detypedef()) if value.lbitsize is not None and value.lbitsize != value.type.size() * 8: typeName += ' : %s' % value.lbitsize self.putBetterType(typeName) @@ -2535,13 +2601,10 @@ class DumperBase: return if typeobj.code == TypeCodeReference: - target = typeobj.target() - if self.isLldb: - item = value.cast(target.pointer()).dereference() - else: - item = value.cast(target.unqualified()) - self.putItem(item) - self.putBetterType(target.name + ' &') + #warn('REFERENCE VALUE: %s' % value) + val = value.dereference() + self.putItem(val) + self.putBetterType(typeName) return if typeobj.code == TypeCodeComplex: @@ -2574,8 +2637,8 @@ class DumperBase: self.putType(typeName) self.putNumChild(1) self.putEmptyValue() - #warn('STRUCT GUTS: %s ADDRESS: %s ' % (value.name, value.address())) - #metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type) + #warn('STRUCT GUTS: %s ADDRESS: 0x%x ' % (value.name, value.address())) + metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type) if self.showQObjectNames: self.preping(self.currentIName) metaObjectPtr = self.extractMetaObjectPtr(value.address(), value.type) @@ -2607,9 +2670,6 @@ class DumperBase: return tiVersion return None - def lookupType(self, typestring): - return self.fromNativeType(self.lookupNativeType(typestring)) - def addToCache(self, typeobj): typename = typeobj.name if typename in self.typesReported: @@ -2622,11 +2682,12 @@ class DumperBase: self.dumper = dumper self.name = None self.type = None - self.ldata = None - self.laddress = None + self.ldata = None # Target address in case of references and pointers. + self.laddress = None # Own address. self.lIsInScope = True self.ldisplay = None self.lbitsize = None + self.targetValue = None # For references. def check(self): if self.laddress is not None and not self.dumper.isInt(self.laddress): @@ -2649,7 +2710,8 @@ class DumperBase: def display(self): if self.type.code == TypeCodeEnum: - return self.type.enumDisplay(self.extractInteger(self.type.bitsize(), False)) + intval = self.extractInteger(self.type.bitsize(), False) + return self.type.typeData.enumDisplay(intval) simple = self.value() if simple is not None: return str(simple) @@ -2663,30 +2725,38 @@ class DumperBase: return 'value of type %s at address 0x%x' % (self.type.name, self.laddress) return '' + def pointer(self): + if self.type.code == TypeCodeTypedef: + return self.detypedef().pointer() + return self.extractInteger(self.dumper.ptrSize() * 8, True) + def integer(self): - unsigned = self.type.stripTypedefs().name.startswith('unsigned') + if self.type.code == TypeCodeTypedef: + return self.detypedef().integer() + unsigned = self.type.name.startswith('unsigned') bitsize = self.type.bitsize() return self.extractInteger(bitsize, unsigned) def floatingPoint(self): + if self.type.code == TypeCodeTypedef: + return self.detypedef().floatingPoint() if self.type.size() == 8: return self.extractSomething('d', 64) if self.type.size() == 4: return self.extractSomething('f', 32) error('BAD FLOAT DATA: %s SIZE: %s' % (self, self.type.size())) - def pointer(self): - return self.extractInteger(8 * self.dumper.ptrSize(), True) - def value(self): if self.type is not None: + if self.type.code == TypeCodeTypedef: + return self.detypedef().value() if self.type.code == TypeCodeIntegral: return self.integer() if self.type.code == TypeCodeFloat: return self.floatingPoint() if self.type.code == TypeCodeTypedef: - return self.cast(self.type.stripTypedefs()).value() - if self.type.stripTypedefs().code == TypeCodePointer: + return self.cast(self.type.ltarget).value() + if self.type.code == TypeCodePointer: return self.pointer() return None @@ -2697,8 +2767,8 @@ class DumperBase: #warn('GET ITEM %s %s' % (self, index)) self.check() if self.type.code == TypeCodeTypedef: - #warn('GET ITEM %s STRIP TYPEDEFS TO %s' % (self, self.type.stripTypedefs())) - return self.cast(self.type.stripTypedefs()).__getitem__(index) + #warn('GET ITEM STRIP TYPEDEFS TO %s' % self.type.ltarget) + return self.cast(self.type.ltarget).__getitem__(index) if isinstance(index, str): if self.type.code == TypeCodePointer: #warn('GET ITEM %s DEREFERENCE TO %s' % (self, self.dereference())) @@ -2725,7 +2795,9 @@ class DumperBase: def extractField(self, field): if self.type.code == TypeCodeTypedef: - return self.cast(self.type.stripTypedefs()).extractField(field) + return self.cast(self.type.ltarget).extractField(field) + if self.type.code == TypeCodeReference: + return self.dereference().extractField(field) if not isinstance(field, self.dumper.Field): error('BAD INDEX TYPE %s' % type(field)) @@ -2756,15 +2828,12 @@ class DumperBase: val.type = None if val.laddress is not None and fieldType is not None: - if fieldType.code in (TypeCodePointer, TypeCodeReference): - baseType = fieldType.dereference() - address = self.dumper.extractPointer(val.laddress) - dynTypeName = self.dumper.dynamicTypeName(baseType, address) - if dynTypeName is not None: - if fieldType.code == TypeCodePointer: - val.type = self.dumper.createType(dynTypeName + '*') - else: - val.type = self.dumper.createType(dynTypeName + ' &') + if fieldType.code == TypeCodePointer: + objectAddress = self.dumper.extractPointer(val.laddress) + val = self.dumper.createPointerValue(objectAddress, fieldType.ltarget) + elif fieldType.code == TypeCodeReference: + objectAddress = self.dumper.extractPointer(val.laddress) + val = self.dumper.createReferenceValue(objectAddress, fieldType.ltarget) if val.type is None: val.type = fieldType @@ -2795,27 +2864,54 @@ class DumperBase: def dereference(self): self.check() + if self.type.code == TypeCodeTypedef: + return self.detypedef().dereference() val = self.dumper.Value(self.dumper) - val.type = self.type.dereference() - val.laddress = self.pointer() - dynTypeName = self.dumper.dynamicTypeName(val.type, val.laddress) - if dynTypeName is not None: - val.type = self.dumper.createType(dynTypeName) + if self.type.code == TypeCodeReference: + val.laddress = self.pointer() + if val.laddress is None and self.laddress is not None: + val.laddress = self.laddress + val.type = self.type.dereference().dynamicType(val.laddress) + elif self.type.code == TypeCodePointer: + val.laddress = self.pointer() + val.type = self.type.dereference().dynamicType(val.laddress) + else: + error("WRONG: %s" % self.type.code) + #warn("DEREFERENCING FROM: %s" % self) + #warn("DEREFERENCING TO: %s" % val) + #dynTypeName = val.type.dynamicTypeName(val.laddress) + #if dynTypeName is not None: + # val.type = self.dumper.createType(dynTypeName) + return val + + def detypedef(self): + self.check() + if self.type.code != TypeCodeTypedef: + error("WRONG") + val = self.dumper.Value(self.dumper) + val.type = self.type.ltarget + val.ldata = self.ldata + val.laddress = self.laddress + #warn("DETYPEDEF FROM: %s" % self) + #warn("DETYPEDEF TO: %s" % val) return val def extend(self, size): if self.type.size() < size: val = self.dumper.Value(self.dumper) val.laddress = None - if sys.version_info[0] == 3: - val.ldata = self.ldata + bytes('\0' * (size - self.type.size()), encoding='latin1') - else: - val.ldata = self.ldata + bytes('\0' * (size - self.type.size())) + val.ldata = self.zeroExtend(self.ldata) return val if self.type.size() == size: return self error('NOT IMPLEMENTED') + def zeroExtend(self, data, size): + if sys.version_info[0] == 3: + return data + bytes('\0' * (size - len(data)), encoding='latin1') + else: + return data + bytes('\0' * (size - len(data))) + def cast(self, typish): self.check() val = self.dumper.Value(self.dumper) @@ -2843,12 +2939,15 @@ class DumperBase: return self.ldata if size < len(self.ldata): return self.ldata[:size] + #error('ZERO-EXTENDING DATA TO %s BYTES: %s' % (size, self)) + return self.zeroExtend(self.ldata, size) if self.laddress is not None: if size is None: size = self.type.size() res = self.dumper.readRawMemory(self.laddress, size) if len(res) > 0: return res + error('CANNOT CONVERT ADDRESS TO BYTES: %s' % self) error('CANNOT CONVERT TO BYTES: %s' % self) def extractInteger(self, bitsize, unsigned): @@ -2892,8 +2991,8 @@ class DumperBase: if field.isStruct: if field.ltype != field.fieldType(): error('DO NOT SIMPLIFY') - #warn('FIELD POS: %s' % field.ltype) - #warn('FIELD TYE: %s' % field.fieldType()) + #warn('FIELD POS: %s' % field.ltype.stringify()) + #warn('FIELD TYE: %s' % field.fieldType().stringify()) res = self.dumper.createValue(thing, field.fieldType()) #warn('RES TYPE: %s' % res.type) if self.laddress is not None: @@ -2908,75 +3007,151 @@ class DumperBase: ptr = p if self.isInt(p) else p.pointer() self.readRawMemory(ptr, 1) - def dynamicTypeName(self, baseType, address): - if baseType.code != TypeCodeStruct: - return None - try: - vtbl = self.extractPointer(address) - except: - return None - #warn('VTBL: 0x%x' % vtbl) - if not self.canBePointer(vtbl): - return None - return self.nativeDynamicTypeName(address, baseType) + def type(self, typeId): + return self.typeData.get(typeId) - class Type: + def registerType(self, typeId, tdata): + #warn('REGISTER TYPE: %s' % typeId) + self.typeData[typeId] = tdata + #typeId = typeId.replace(' ', '') + #self.typeData[typeId] = tdata + #warn('REGISTERED: %s' % self.typeData) + + def registerTypeAlias(self, existingTypeId, aliasId): + #warn('REGISTER ALIAS %s FOR %s' % (aliasId, existingTypeId)) + self.typeData[aliasId] = self.typeData[existingTypeId] + + class TypeData: def __init__(self, dumper): self.dumper = dumper - self.name = None - self.nativeType = None - self.lfields = None + self.lfields = [] self.lbitsize = None self.lbitpos = None self.ltarget = None # Inner type for arrays - self.templateArguments = None + self.templateArguments = [] self.code = None + self.name = None + self.typeId = None + self.enumDisplay = str + + class Type: + def __init__(self, dumper, typeId): + self.typeId = typeId + self.dumper = dumper def __str__(self): - self.check() - error('Not implemented') - return self.name - #error('Not implemented') + #return self.typeId + return self.stringify() + + @property + def typeData(self): + tdata = self.dumper.typeData.get(self.typeId, None) + if tdata is not None: + #warn('USING : %s' % self.typeId) + return tdata + typeId = self.typeId.replace(' ', '') + if tdata is not None: + #warn('USING FALLBACK : %s' % self.typeId) + return tdata + #warn('EXPANDING LAZILY: %s' % self.typeId) + self.dumper.lookupType(self.typeId) + return self.dumper.typeData.get(self.typeId) + + @property + def name(self): + tdata = self.typeData + if tdata is None: + return self.typeId + return tdata.name + + @property + def code(self): + return self.typeData.code + + @property + def lbitsize(self): + return self.typeData.lbitsize + + @property + def lbitpos(self): + return self.typeData.lbitpos + + @property + def ltarget(self): + return self.typeData.ltarget + + @property + def lfields(self): + return self.typeData.lfields def stringify(self): - return 'Type(name="%s",bsize=%s,bpos=%s,code=%s,ntype=%s)' \ - % (self.name, self.lbitsize, self.lbitpos, self.code, self.nativeType) + tdata = self.typeData + if tdata is None: + return 'Type(id="%s")' % self.typeId + return 'Type(name="%s",bsize=%s,bpos=%s,code=%s)' \ + % (tdata.name, tdata.lbitsize, tdata.lbitpos, tdata.code) def __getitem__(self, index): if self.dumper.isInt(index): return self.templateArgument(index) error('CANNOT INDEX TYPE') + def dynamicTypeName(self, address): + tdata = self.typeData + if tdata is None: + return None + if tdata.code != TypeCodeStruct: + return None + try: + vtbl = self.dumper.extractPointer(address) + except: + return None + #warn('VTBL: 0x%x' % vtbl) + if not self.dumper.canBePointer(vtbl): + return None + return self.dumper.nativeDynamicTypeName(address, self) + + def dynamicType(self, address): + dynTypeName = self.dynamicTypeName(address) + if dynTypeName is not None: + return self.dumper.createType(dynTypeName) + return self + def check(self): - if self.name is None: - error('TYPE WITHOUT NAME') + tdata = self.typeData + if tdata is None: + error('TYPE WITHOUT DATA: %s ALL: %s' % (self.typeId, self.dumper.typeData.keys())) + if tdata.name is None: + error('TYPE WITHOUT NAME: %s' % self.typeId) def dereference(self): + if self.code == TypeCodeTypedef: + return self.ltarget.dereference() self.check() - if self.nativeType is not None: - return self.dumper.nativeTypeDereference(self.nativeType) - error('DONT KNOW HOW TO DEREF: %s' % self.name) + return self.ltarget def unqualified(self): - if self.nativeType is not None: - return self.dumper.nativeTypeUnqualified(self.nativeType) return self def templateArgument(self, position, numeric = False): - if self.templateArguments is not None: - return self.templateArguments[position] - nativeType = self.nativeType - #warn('NATIVE TYPE 0: %s' % dir(nativeType)) - if nativeType is None: - nativeType = self.dumper.lookupNativeType(self.name) - #warn('NATIVE TYPE 1: %s' % dir(nativeType)) - if nativeType is not None: - return self.dumper.nativeTypeTemplateArgument(nativeType, position, numeric) - res = self.dumper.extractTemplateArgument(self.name, position) - #warn('TEMPLATE ARG: RES: %s' % res) - if numeric: - return int(res) - return self.dumper.createType(res) + tdata = self.typeData + #warn('TDATA: %s' % tdata) + #warn('ID: %s' % self.typeId) + if tdata is None: + # Native lookups didn't help. Happens for 'wrong' placement of 'const' + # etc. with LLDB. But not all is lost: + ta = self.dumper.listTemplateParameters(self.typeId) + #warn('MANUAL: %s' % ta) + res = ta[position] + #warn('RES: %s' % res.typeId) + return res + #warn('TA: %s %s' % (position, self.typeId)) + #warn('ARGS: %s' % tdata.templateArguments) + res = tdata.templateArguments[position] + #if tdata.templateArguments is not None: + #if numeric: + # return tdata.templateArguments[position].value() + return res def simpleEncoding(self): res = { @@ -2999,10 +3174,11 @@ class DumperBase: return self.code in (TypeCodeIntegral, TypeCodeFloat, TypeCodeEnum) def alignment(self): + #warn('ALIGN: %s' % self.stringify()) if self.code == TypeCodeTypedef: - return self.stripTypedefs().alignment() + return self.ltarget.alignment() if self.isSimpleType(): - if self.name == 'double': + if self.name in ('double', 'long long', 'unsigned long long'): return self.dumper.ptrSize() # Crude approximation. return self.size() if self.code == TypeCodePointer: @@ -3010,6 +3186,7 @@ class DumperBase: fields = self.fields() align = 1 for field in fields: + #warn(' SUBFIELD: %s TYPE %s' % (field.name, field.fieldType().name)) a = field.fieldType().alignment() #warn(' SUBFIELD: %s ALIGN: %s' % (field.name, a)) if a is not None and a > align: @@ -3018,9 +3195,7 @@ class DumperBase: return align def pointer(self): - if self.nativeType is not None: - return self.dumper.nativeTypePointer(self.nativeType) - error('Cannot create pointer type for %s' % self) + return self.dumper.createPointerType(self) def splitArrayType(self): # -> (inner type, count) @@ -3033,44 +3208,17 @@ class DumperBase: return (self.dumper.createType(s[0:pos1].strip()), int(s[pos1+1:pos2])) def target(self): - if self.nativeType is not None: - target = self.dumper.nativeTypeTarget(self.nativeType) - #warn('DEREFERENCING: %s -> %s ' % (self.nativeType, target)) - if target is not None: - return target - if self.code == TypeCodeArray: - (innerType, itemCount) = self.splitArrayType() - #warn('EXTRACTING ARRAY TYPE: %s -> %s' % (self, innerType)) - # HACK for LLDB 320: - if innerType.code is None and innerType.name.endswith(']'): - innerType.code = TypeCodeArray - return innerType - - strippedType = self.stripTypedefs() - if strippedType.name != self.name: - return strippedType.target() - error('DONT KNOW TARGET FOR: %s' % self) + return self.typeData.ltarget def fields(self): - #warn('GETTING FIELDS FOR: %s' % self.name) - if self.lfields is not None: - warn('USING LFIELDS: %s' % self.lfields) - return self.lfields - nativeType = self.nativeType - if nativeType is None: - nativeType = self.dumper.lookupNativeType(self.name) - #warn('FIELDS LOOKING UP NATIVE TYPE FOR %s -> %s' % (self.name, nativeType)) - if nativeType is not None: - #warn('FIELDS USING NATIVE TYPE %s' % nativeType) - fields = self.dumper.nativeTypeFields(nativeType) - #warn('FIELDS RES: %s FOR %s' % (fields, nativeType)) - return fields - error('DONT KNOW FIELDS FOR: %s' % self.stringify()) - return [] + if self.code == TypeCodeTypedef: + return self.ltarget.fields() + return self.lfields def firstBase(self): - if self.nativeType is not None: - return self.dumper.nativeTypeFirstBase(self.nativeType) + lfields = self.fields() + if len(lfields) > 0 and lfields[0].isBaseClass: + return lfields[0].ltype return None def field(self, name, bitoffset = 0): @@ -3094,14 +3242,10 @@ class DumperBase: return None def stripTypedefs(self): - if self.code != TypeCodeTypedef: + if isinstance(self, self.dumper.Type) and self.code != TypeCodeTypedef: #warn('NO TYPEDEF: %s' % self) return self - if self.nativeType is not None: - res = self.dumper.nativeTypeStripTypedefs(self.nativeType) - #warn('STRIP TYPEDEF: %s -> %s' % (self, res)) - return res - error('DONT KNOW HOW TO STRIP TYPEDEFS FROM %s' % s) + return self.ltarget def size(self): bs = self.bitsize() @@ -3136,11 +3280,6 @@ class DumperBase: return True return strippedName == 'QStringList' and self.dumper.qtVersion() >= 0x050000 - def enumDisplay(self, intval): - if self.nativeType is not None: - return self.dumper.nativeTypeEnumDisplay(self.nativeType, intval) - return '%d' % intval - class Field: def __init__(self, dumper): self.dumper = dumper @@ -3159,8 +3298,8 @@ class DumperBase: return ('Field(name="%s",ltype=%s,parentType=%s,bpos=%s,bsize=%s,' + 'bidx=%s,nidx=%s)') \ % (self.name, - None if self.ltype is None else self.ltype.name, - None if self.parentType is None else self.parentType.name, + self.ltype.stringify(), + self.parentType.typeId, self.lbitpos, self.lbitsize, self.baseIndex, self.nativeIndex) @@ -3207,11 +3346,122 @@ class DumperBase: #error('CANT GET FIELD TYPE FOR %s' % self) return None + def toPointerData(self, address): + if not self.isInt(address): + error('wrong') + size = self.ptrSize() + code = 'I' if size == 4 else 'Q' + return bytes(struct.pack(code, address)) + + def createPointerValue(self, targetAddress, targetType): + if not isinstance(targetType, self.Type): + error('Expected type in createPointerValue(), got %s' + % type(targetType)) + if not self.isInt(targetAddress): + error('Expected integral address value in createPointerValue(), got %s' + % type(targetType)) + val = self.Value(self) + val.ldata = self.toPointerData(targetAddress) + targetType = targetType.dynamicType(targetAddress) + val.type = self.createPointerType(targetType) + return val + + def createReferenceValue(self, targetAddress, targetType): + if not isinstance(targetType, self.Type): + error('Expected type in createReferenceValue(), got %s' + % type(targetType)) + if not self.isInt(targetAddress): + error('Expected integral address value in createReferenceValue(), got %s' + % type(targetType)) + val = self.Value(self) + val.ldata = self.toPointerData(targetAddress) + targetType = targetType.dynamicType(targetAddress) + val.type = self.createReferenceType(targetType) + return val + + def createPointerType(self, targetType): + if not isinstance(targetType, self.Type): + error('Expected type in createPointerType(), got %s' + % type(targetType)) + typeId = targetType.typeId + ' *' + tdata = self.TypeData(self) + tdata.name = targetType.name + '*' + tdata.typeId = typeId + tdata.lbitsize = 8 * self.ptrSize() + tdata.code = TypeCodePointer + tdata.ltarget = targetType + tdata.lfields = [] + self.registerType(typeId, tdata) + return self.Type(self, typeId) + + def createReferenceType(self, targetType): + if not isinstance(targetType, self.Type): + error('Expected type in createReferenceType(), got %s' + % type(targetType)) + typeId = targetType.typeId + ' &' + tdata = self.TypeData(self) + tdata.name = targetType.name + ' &' + tdata.typeId = typeId + tdata.code = TypeCodeReference + tdata.ltarget = targetType + tdata.lbitsize = 8 * self.ptrSize() # Needed for Gdb13393 test. + #tdata.lbitsize = None + self.registerType(typeId, tdata) + return self.Type(self, typeId) + + def createArrayType(self, targetType, count): + if not isinstance(targetType, self.Type): + error('Expected type in createArrayType(), got %s' + % type(targetType)) + typeId = '%s[%d]' % (targetType.typeId, count) + tdata = self.TypeData(self) + tdata.name = '%s[%d]' % (targetType.name, count) + tdata.typeId = typeId + tdata.code = TypeCodeArray + tdata.ltarget = targetType + tdata.lbitsize = count * targetType.lbitsize + fields = [] + for i in range(count): + field = self.Field(self) + field.ltype = targetType + field.parentType = None + field.isBaseClass = False + field.lbitsize = targetType.lbitsize + field.lbitpos = i * targetType.lbitsize * 8 + fields.append(field) + #tdata.lfields = fields + self.registerType(typeId, tdata) + return self.Type(self, typeId) + + def createTypedefedType(self, targetType, typeId): + if not isinstance(targetType, self.Type): + error('Expected type in createTypedefType(), got %s' + % type(targetType)) + # Happens for C-style struct in GDB: typedef { int x; } struct S1; + if targetType.typeId == typeId: + return targetType + tdata = self.TypeData(self) + tdata.name = typeId + tdata.typeId = typeId + tdata.code = TypeCodeTypedef + tdata.ltarget = targetType + tdata.lbitsize = targetType.lbitsize + tdata.lfields = targetType.lfields + self.registerType(typeId, tdata) + return self.Type(self, typeId) + def createType(self, typish, size = None): if isinstance(typish, self.Type): - typish.check() + #typish.check() return typish if isinstance(typish, str): + if typish.endswith(']') and not typish.endswith('[]'): + # Array fallback. + pos1 = typish.rfind('[') + itemType = self.createType(typish[0:pos1].strip()) + itemCount = int(typish[pos1+1:-1]) + return self.createArrayType(itemType, itemCount) + def knownSize(tn): if tn[0] == 'Q': if tn in ('QByteArray', 'QString', 'QList', 'QStringList', @@ -3234,26 +3484,35 @@ class DumperBase: ns = self.qtNamespace() typish = typish.replace('@', ns) if typish.startswith(ns): - size = knownSize(typish[len(ns):]) + if size is None: + size = knownSize(typish[len(ns):]) else: - size = knownSize(typish) + if size is None: + size = knownSize(typish) if size is not None: typish = ns + typish - #typeobj = self.Type(self) - #typeobj.name = typish - nativeType = self.lookupNativeType(typish) # FIXME: Remove? - #warn('FOUND NAT TYPE: %s' % dir(nativeType)) - if nativeType is not None: + + tdata = self.typeData.get(typish, None) + if tdata is not None: + return self.Type(self, typish) + + knownType = self.lookupType(typish) + #warn('KNOWN: %s' % knownType) + if knownType is not None: #warn('USE FROM NATIVE') - typeobj = self.fromNativeType(nativeType) - else: - #warn('FAKING') - typeobj = self.Type(self) - typeobj.name = typish - if size is not None: - typeobj.lbitsize = 8 * size - #warn('CREATE TYPE: %s' % typeobj) + return knownType + + #warn('FAKING: %s SIZE: %s' % (typish, size)) + tdata = self.TypeData(self) + tdata.name = typish + tdata.typeId = typish + + if size is not None: + tdata.lbitsize = 8 * size + self.registerType(typish, tdata) + typeobj = self.Type(self, typish) + #warn('CREATE TYPE: %s' % typeobj.stringify()) typeobj.check() return typeobj error('NEED TYPE, NOT %s' % type(typish)) @@ -3262,38 +3521,37 @@ class DumperBase: val = self.Value(self) val.type = self.createType(typish) if self.isInt(datish): # Used as address. + #warn('CREATING %s AT 0x%x' % (val.type.name, datish)) val.laddress = datish - #warn('CREATING %s AT 0x%x' % (val.type.name, address)) - elif isinstance(datish, bytes): - val.ldata = datish - val.type.lbitsize = 8 * len(datish) + val.type = val.type.dynamicType(datish) + return val + if isinstance(datish, bytes): #warn('CREATING %s WITH DATA %s' % (val.type.name, self.hexencode(datish))) - else: - error('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish)) - val.check() + val.ldata = datish + val.check() + return val + error('EXPECTING ADDRESS OR BYTES, GOT %s' % type(datish)) + + def createContainerItem(self, data, innerTypish, container): + innerType = self.createType(innerTypish) + name = self.qtNamespace() + '%s<%s>' % (container, innerType.name) + typeId = name + tdata = self.TypeData(self) + tdata.typeId = typeId + tdata.name = name + tdata.templateArguments = [innerType] + tdata.lbitsize = 8 * self.ptrSize() + self.registerType(typeId, tdata) + val = self.Value(self) + val.ldata = data + val.type = self.Type(self, typeId) return val def createListItem(self, data, innerTypish): - innerType = self.createType(innerTypish) - typeobj = self.Type(self) - typeobj.name = self.qtNamespace() + 'QList<%s>' % innerType.name - typeobj.templateArguments = [innerType] - typeobj.lbitsize = 8 * self.ptrSize() - val = self.Value(self) - val.ldata = data - val.type = typeobj - return val + return self.createContainerItem(data, innerTypish, 'QList') def createVectorItem(self, data, innerTypish): - innerType = self.createType(innerTypish) - typeobj = self.Type(self) - typeobj.name = self.qtNamespace() + 'QVector<%s>' % innerType.name - typeobj.templateArguments = [innerType] - typeobj.lbitsize = 8 * self.ptrSize() - val = self.Value(self) - val.ldata = data - val.type = typeobj - return val + return self.createContainerItem(data, innerTypish, 'QVector') class StructBuilder: def __init__(self, dumper): diff --git a/share/qtcreator/debugger/gdbbridge.py b/share/qtcreator/debugger/gdbbridge.py index 9ab49555f51..b1db09ad15d 100644 --- a/share/qtcreator/debugger/gdbbridge.py +++ b/share/qtcreator/debugger/gdbbridge.py @@ -205,17 +205,46 @@ class Dumper(DumperBase): self.output = [] self.setVariableFetchingOptions(args) - def fromNativeDowncastableValue(self, nativeValue): + def fromFrameValue(self, nativeValue): + val = nativeValue if self.useDynamicType: try: - return self.fromNativeValue(nativeValue.cast(nativeValue.dynamic_type)) + val = nativeValue.cast(nativeValue.dynamic_type) except: pass - return self.fromNativeValue(nativeValue) + return self.fromNativeValue(val) def fromNativeValue(self, nativeValue): - #self.check(isinstance(nativeValue, gdb.Value)) + #warn("FROM NATIVE VALUE: %s" % nativeValue) + self.check(isinstance(nativeValue, gdb.Value)) nativeType = nativeValue.type + code = nativeType.code + if code == gdb.TYPE_CODE_REF: + targetType = self.fromNativeType(nativeType.target().unqualified()) + val = self.createReferenceValue(toInteger(nativeValue.address), targetType) + #warn("CREATED REF: %s" % val) + return val + if code == gdb.TYPE_CODE_PTR: + targetType = self.fromNativeType(nativeType.target().unqualified()) + val = self.createPointerValue(toInteger(nativeValue), targetType) + #warn("CREATED PTR 1: %s" % val) + if not nativeValue.address is None: + val.laddress = toInteger(nativeValue.address) + #warn("CREATED PTR 2: %s" % val) + return val + if code == gdb.TYPE_CODE_TYPEDEF: + targetType = nativeType.strip_typedefs().unqualified() + #warn("TARGET TYPE: %s" % targetType) + if targetType.code == gdb.TYPE_CODE_ARRAY: + val = self.Value(self) + val.laddress = toInteger(nativeValue.address) + else: + # Cast may fail (e.g for arrays, see test for Bug5799) + val = self.fromNativeValue(nativeValue.cast(targetType)) + val.type = self.fromNativeType(nativeType) + #warn("CREATED TYPEDEF: %s" % val) + return val + val = self.Value(self) if not nativeValue.address is None: val.laddress = toInteger(nativeValue.address) @@ -238,82 +267,131 @@ class Dumper(DumperBase): val.ldisplay += ' (%s)' % intval elif code == gdb.TYPE_CODE_COMPLEX: val.ldisplay = str(nativeValue) - elif code == gdb.TYPE_CODE_ARRAY: - val.type.ltarget = nativeValue[0].type.unqualified() + #elif code == gdb.TYPE_CODE_ARRAY: + # val.type.ltarget = nativeValue[0].type.unqualified() return val + def ptrSize(self): + result = gdb.lookup_type('void').pointer().sizeof + self.ptrSize = lambda: result + return result + def fromNativeType(self, nativeType): self.check(isinstance(nativeType, gdb.Type)) - typeobj = self.Type(self) - typeobj.nativeType = nativeType.unqualified() - typeobj.name = str(typeobj.nativeType) - typeobj.lbitsize = nativeType.sizeof * 8 - typeobj.code = { - gdb.TYPE_CODE_TYPEDEF : TypeCodeTypedef, - gdb.TYPE_CODE_METHOD : TypeCodeFunction, - gdb.TYPE_CODE_VOID : TypeCodeVoid, - gdb.TYPE_CODE_FUNC : TypeCodeFunction, - gdb.TYPE_CODE_METHODPTR : TypeCodeFunction, - gdb.TYPE_CODE_MEMBERPTR : TypeCodeFunction, - gdb.TYPE_CODE_PTR : TypeCodePointer, - gdb.TYPE_CODE_REF : TypeCodeReference, - gdb.TYPE_CODE_BOOL : TypeCodeIntegral, - gdb.TYPE_CODE_CHAR : TypeCodeIntegral, - gdb.TYPE_CODE_INT : TypeCodeIntegral, - gdb.TYPE_CODE_FLT : TypeCodeFloat, - gdb.TYPE_CODE_ENUM : TypeCodeEnum, - gdb.TYPE_CODE_ARRAY : TypeCodeArray, - gdb.TYPE_CODE_STRUCT : TypeCodeStruct, - gdb.TYPE_CODE_UNION : TypeCodeStruct, - gdb.TYPE_CODE_COMPLEX : TypeCodeComplex, - gdb.TYPE_CODE_STRING : TypeCodeFortranString, - }[nativeType.code] - return typeobj + code = nativeType.code + #warn('FROM NATIVE TYPE: %s' % nativeType) + #nativeType = nativeType.unqualified() - def nativeTypeDereference(self, nativeType): - return self.fromNativeType(nativeType.strip_typedefs().target()) + if code == gdb.TYPE_CODE_PTR: + #warn('PTR') + targetType = self.fromNativeType(nativeType.target().unqualified()) + return self.createPointerType(targetType) - def nativeTypeUnqualified(self, nativeType): - return self.fromNativeType(nativeType.unqualified()) + if code == gdb.TYPE_CODE_REF: + #warn('REF') + targetType = self.fromNativeType(nativeType.target().unqualified()) + return self.createReferenceType(targetType) - def nativeTypePointer(self, nativeType): - return self.fromNativeType(nativeType.pointer()) + if code == gdb.TYPE_CODE_ARRAY: + #warn('ARRAY') + nativeTargetType = nativeType.target().unqualified() + targetType = self.fromNativeType(nativeTargetType) + count = nativeType.sizeof // nativeTargetType.sizeof + return self.createArrayType(targetType, count) - def nativeTypeTarget(self, nativeType): - while nativeType.code == gdb.TYPE_CODE_TYPEDEF: - nativeType = nativeType.strip_typedefs().unqualified() - return self.fromNativeType(nativeType.target()) + if code == gdb.TYPE_CODE_TYPEDEF: + #warn('TYPEDEF') + nativeTargetType = nativeType.unqualified() + while nativeTargetType.code == gdb.TYPE_CODE_TYPEDEF: + nativeTargetType = nativeTargetType.strip_typedefs().unqualified() + targetType = self.fromNativeType(nativeTargetType) + return self.createTypedefedType(targetType, str(nativeType)) - def nativeTypeFirstBase(self, nativeType): - nativeFields = nativeType.fields() - if len(nativeFields) and nativeFields[0].is_base_class: - return self.fromNativeType(nativeFields[0].type) + if code == gdb.TYPE_CODE_ERROR: + warn('Type error: %s' % nativeType) + return self.Type(self, '') + + typeId = self.nativeTypeId(nativeType) + res = self.typeData.get(typeId, None) + if res is None: + tdata = self.TypeData(self) + tdata.name = str(nativeType) + tdata.typeId = typeId + tdata.lbitsize = nativeType.sizeof * 8 + tdata.code = { + #gdb.TYPE_CODE_TYPEDEF : TypeCodeTypedef, # Handled above. + gdb.TYPE_CODE_METHOD : TypeCodeFunction, + gdb.TYPE_CODE_VOID : TypeCodeVoid, + gdb.TYPE_CODE_FUNC : TypeCodeFunction, + gdb.TYPE_CODE_METHODPTR : TypeCodeFunction, + gdb.TYPE_CODE_MEMBERPTR : TypeCodeFunction, + #gdb.TYPE_CODE_PTR : TypeCodePointer, # Handled above. + #gdb.TYPE_CODE_REF : TypeCodeReference, # Handled above. + gdb.TYPE_CODE_BOOL : TypeCodeIntegral, + gdb.TYPE_CODE_CHAR : TypeCodeIntegral, + gdb.TYPE_CODE_INT : TypeCodeIntegral, + gdb.TYPE_CODE_FLT : TypeCodeFloat, + gdb.TYPE_CODE_ENUM : TypeCodeEnum, + #gdb.TYPE_CODE_ARRAY : TypeCodeArray, + gdb.TYPE_CODE_STRUCT : TypeCodeStruct, + gdb.TYPE_CODE_UNION : TypeCodeStruct, + gdb.TYPE_CODE_COMPLEX : TypeCodeComplex, + gdb.TYPE_CODE_STRING : TypeCodeFortranString, + }[code] + if tdata.code == TypeCodeEnum: + tdata.enumDisplay = lambda intval: self.nativeTypeEnumDisplay(nativeType, intval) + self.registerType(typeId, tdata) # Prevent recursion in fields. + tdata.lfields = self.listFields(nativeType, self.Type(self, typeId)) + tdata.templateArguments = self.listTemplateParameters(nativeType) + self.registerType(typeId, tdata) # Fix up fields and template args + # warn('CREATE TYPE: %s' % typeId) + #else: + # warn('REUSE TYPE: %s' % typeId) + return self.Type(self, typeId) + + def listTemplateParameters(self, nativeType): + targs = [] + pos = 0 + while True: + try: + targ = nativeType.template_argument(pos) + except: + break + if isinstance(targ, gdb.Type): + targs.append(self.fromNativeType(targ.unqualified())) + elif isinstance(targ, gdb.Value): + #targs.append(self.fromNativeValue(targ)) + targs.append(self.fromNativeValue(targ).value()) + else: + error('CRAP') + pos += 1 + return targs def nativeTypeEnumDisplay(self, nativeType, intval): try: - val = gdb.parse_and_eval("(%s)%d" % (nativeType, intval)) - return "%s (%d)" % (val, intval) + val = gdb.parse_and_eval('(%s)%d' % (nativeType, intval)) + return '%s (%d)' % (val, intval) except: - return "%d" % intval + return '%d' % intval - def nativeTypeFields(self, nativeType): - if nativeType.code == gdb.TYPE_CODE_TYPEDEF: - return self.nativeTypeFields(nativeType.strip_typedefs()) + def nativeTypeId(self, nativeType): + name = str(nativeType) + if len(name) == 0: + c = '0' + elif name == 'struct {...}': + c = 's' + elif name == 'union {...}': + c = 'u' + else: + return name + typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.type)) for f in nativeType.fields()]) + return typeId + + def listFields(self, nativeType, parentType): + #if nativeType.code == gdb.TYPE_CODE_TYPEDEF: + # return self.listFields(nativeType.strip_typedefs(), parentType) fields = [] - if nativeType.code == gdb.TYPE_CODE_ARRAY: - # An array. - typeobj = nativeType.strip_typedefs() - innerType = typeobj.target() - for i in xrange(int(typeobj.sizeof / innerType.sizeof)): - field = self.Field(self) - field.ltype = self.fromNativeType(innerType) - field.parentType = self.fromNativeType(nativeType) - field.isBaseClass = False - field.lbitsize = innerType.sizeof - field.lbitpos = i * innerType.sizeof * 8 - fields.append(field) - return fields if not nativeType.code in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION): return fields @@ -321,18 +399,20 @@ class Dumper(DumperBase): nativeIndex = 0 baseIndex = 0 nativeFields = nativeType.fields() - #warn("NATIVE FIELDS: %s" % nativeFields) + #warn('NATIVE FIELDS: %s' % nativeFields) + anonNumber = 0 for nativeField in nativeFields: - #warn("FIELD: %s" % nativeField) - #warn(" DIR: %s" % dir(nativeField)) - #warn(" BITSIZE: %s" % nativeField.bitsize) - #warn(" ARTIFICIAL: %s" % nativeField.artificial) - #warn("FIELD NAME: %s" % nativeField.name) - #warn("FIELD TYPE: %s" % nativeField.type) + #warn('FIELD: %s' % nativeField) + #warn(' DIR: %s' % dir(nativeField)) + #warn(' BITSIZE: %s' % nativeField.bitsize) + #warn(' ARTIFICIAL: %s' % nativeField.artificial) + #warn('FIELD NAME: %s' % nativeField.name) + #warn('FIELD TYPE: %s' % nativeField.type) + #warn('FIELD TYPE ID: %s' % self.nativeTypeId(nativeField.type)) #self.check(isinstance(nativeField, gdb.Field)) field = self.Field(self) - field.ltype = self.fromNativeType(nativeField.type) - field.parentType = self.fromNativeType(nativeType) + field.ltype = self.fromNativeType(nativeField.type.unqualified()) + field.parentType = parentType field.name = nativeField.name field.isBaseClass = nativeField.is_base_class if hasattr(nativeField, 'bitpos'): @@ -356,36 +436,31 @@ class Dumper(DumperBase): # Something without a name. # Anonymous union? We need a dummy name to distinguish # multiple anonymous unions in the struct. - self.anonNumber += 1 - field.name = "#%s" % self.anonNumber + anonNumber += 1 + field.name = '#%s' % anonNumber else: # Normal named field. field.name = nativeField.name field.nativeIndex = nativeIndex + #warn('FIELD RESULT: %s' % field) fields.append(field) nativeIndex += 1 - #warn("FIELDS: %s" % fields) + #warn('FIELDS: %s' % fields) return fields - def nativeTypeStripTypedefs(self, typeobj): - typeobj = typeobj.unqualified() - while typeobj.code == gdb.TYPE_CODE_TYPEDEF: - typeobj = typeobj.strip_typedefs().unqualified() - return self.fromNativeType(typeobj) - def listOfLocals(self, partialVar): frame = gdb.selected_frame() try: block = frame.block() - #warn("BLOCK: %s " % block) + #warn('BLOCK: %s ' % block) except RuntimeError as error: - #warn("BLOCK IN FRAME NOT ACCESSIBLE: %s" % error) + #warn('BLOCK IN FRAME NOT ACCESSIBLE: %s' % error) return [] except: - warn("BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS") + warn('BLOCK NOT ACCESSIBLE FOR UNKNOWN REASONS') return [] items = [] @@ -409,10 +484,18 @@ class Dumper(DumperBase): # "NotImplementedError: Symbol type not yet supported in # Python scripts." #warn("SYMBOL %s (%s, %s)): " % (symbol, name, symbol.name)) - try: - value = self.fromNativeDowncastableValue(frame.read_var(name, block)) - #warn("READ 1: %s" % value) + if False and self.passExceptions: + value = self.fromFrameValue(frame.read_var(name, block)) value.name = name + #warn("READ 1: %s" % value.stringify()) + items.append(value) + continue + + try: + # Same as above, but for production. + value = self.fromFrameValue(frame.read_var(name, block)) + value.name = name + #warn("READ 1: %s" % value.stringify()) items.append(value) continue except: @@ -420,7 +503,7 @@ class Dumper(DumperBase): try: #warn("READ 2: %s" % item.value) - value = self.fromNativeDowncastableValue(frame.read_var(name)) + value = self.fromFrameValue(frame.read_var(name)) value.name = name items.append(value) continue @@ -435,7 +518,8 @@ class Dumper(DumperBase): try: #warn("READ 3: %s %s" % (name, item.value)) #warn("ITEM 3: %s" % item.value) - value = self.fromNativeDowncastableValue(gdb.parse_and_eval(name)) + value = self.fromFrameValue(gdb.parse_and_eval(name)) + value.name = name items.append(value) except: # Can happen in inlined code (see last line of @@ -550,10 +634,11 @@ class Dumper(DumperBase): exp = "((%s*)0x%x)->%s(%s)" % (typeName, addr, function, arg) #warn("CALL: %s" % exp) result = gdb.parse_and_eval(exp) - #warn(" -> %s" % result) + warn(" -> %s" % result) + res = self.fromNativeValue(result) if not value.address(): gdb.parse_and_eval("free((void*)0x%x)" % addr) - return self.fromNativeValue(result) + return res def makeExpression(self, value): typename = "::" + value.type.name @@ -573,13 +658,6 @@ class Dumper(DumperBase): #warn(" VALUE: %s" % value) return value - def nativeTypeTemplateArgument(self, nativeType, position, numeric): - #warn("NATIVE TYPE: %s" % dir(nativeType)) - arg = nativeType.template_argument(position) - if numeric: - return int(str(arg)) - return self.fromNativeType(arg) - def pokeValue(self, value): # Allocates inferior memory and copies the contents of value. # Returns a pointer to the copy. @@ -885,9 +963,6 @@ class Dumper(DumperBase): def enumExpression(self, enumType, enumValue): return self.qtNamespace() + "Qt::" + enumValue - def lookupType(self, typeName): - return self.fromNativeType(self.lookupNativeType(typeName)) - def lookupNativeType(self, typeName): nativeType = self.lookupNativeTypeHelper(typeName) if not nativeType is None: @@ -1154,7 +1229,7 @@ class CliDumper(Dumper): def putNumChild(self, numchild): pass - def putOriginalAddress(self, value): + def putOriginalAddress(self, address): pass def fetchVariables(self, args): @@ -1205,4 +1280,4 @@ class InterpreterMessageBreakpoint(gdb.Breakpoint): print("Interpreter event received.") return theDumper.handleInterpreterMessage() -InterpreterMessageBreakpoint() +#InterpreterMessageBreakpoint() diff --git a/share/qtcreator/debugger/lldbbridge.py b/share/qtcreator/debugger/lldbbridge.py index a1b336e966f..24b3d6ada15 100644 --- a/share/qtcreator/debugger/lldbbridge.py +++ b/share/qtcreator/debugger/lldbbridge.py @@ -44,7 +44,7 @@ from dumper import * qqWatchpointOffset = 10000 def showException(msg, exType, exValue, exTraceback): - warn("**** CAUGHT EXCEPTION: %s ****" % msg) + warn('**** CAUGHT EXCEPTION: %s ****' % msg) import traceback lines = [line for line in traceback.format_exception(exType, exValue, exTraceback)] warn('\n'.join(lines)) @@ -55,13 +55,16 @@ def fileNameAsString(file): def check(exp): if not exp: - raise RuntimeError("Check failed") + raise RuntimeError('Check failed') class Dumper(DumperBase): def __init__(self): DumperBase.__init__(self) lldb.theDumper = self + self.isLldb = True + self.typeCache = {} + self.outputLock = threading.Lock() self.debugger = lldb.SBDebugger.Create() #self.debugger.SetLoggingCallback(loggingCallback) @@ -69,18 +72,18 @@ class Dumper(DumperBase): # s = args.strip() # s = s.replace('"', "'") # sys.stdout.write('log="%s"@\n' % s) - #Same as: self.debugger.HandleCommand("log enable lldb dyld step") - #self.debugger.EnableLog("lldb", ["dyld", "step", "process", "state", - # "thread", "events", - # "communication", "unwind", "commands"]) - #self.debugger.EnableLog("lldb", ["all"]) + #Same as: self.debugger.HandleCommand('log enable lldb dyld step') + #self.debugger.EnableLog('lldb', ['dyld', 'step', 'process', 'state', + # 'thread', 'events', + # 'communication', 'unwind', 'commands']) + #self.debugger.EnableLog('lldb', ['all']) self.debugger.Initialize() - self.debugger.HandleCommand("settings set auto-confirm on") + self.debugger.HandleCommand('settings set auto-confirm on') - # FIXME: warn("DISABLING DEFAULT FORMATTERS") + # FIXME: warn('DISABLING DEFAULT FORMATTERS') # It doesn't work at all with 179.5 and we have some bad # interaction in 300 - # if not hasattr(lldb.SBType, 'GetCanonicalType'): # "Test" for 179.5 + # if not hasattr(lldb.SBType, 'GetCanonicalType'): # 'Test' for 179.5 #self.debugger.HandleCommand('type category delete gnu-libstdc++') #self.debugger.HandleCommand('type category delete libcxx') #self.debugger.HandleCommand('type category delete default') @@ -109,24 +112,67 @@ class Dumper(DumperBase): self.interpreterBreakpointResolvers = [] self.report('lldbversion=\"%s\"' % lldb.SBDebugger.GetVersionString()) - self.reportState("enginesetupok") + self.reportState('enginesetupok') self.debuggerCommandInProgress = False + def fromNativeFrameValue(self, nativeValue): + return self.fromNativeValue(nativeValue) + def fromNativeValue(self, nativeValue): + self.check(isinstance(nativeValue, lldb.SBValue)) nativeValue.SetPreferSyntheticValue(False) nativeType = nativeValue.GetType() + code = nativeType.GetTypeClass() + if code == lldb.eTypeClassReference: + nativeTargetType = nativeType.GetDereferencedType() + if not nativeTargetType.IsPointerType(): + nativeTargetType = nativeTargetType.GetUnqualifiedType() + targetType = self.fromNativeType(nativeTargetType) + val = self.createReferenceValue(nativeValue.GetValueAsUnsigned(), targetType) + val.laddress = nativeValue.AddressOf().GetValueAsUnsigned() + #warn('CREATED REF: %s' % val) + return val + if code == lldb.eTypeClassPointer: + nativeTargetType = nativeType.GetPointeeType() + if not nativeTargetType.IsPointerType(): + nativeTargetType = nativeTargetType.GetUnqualifiedType() + targetType = self.fromNativeType(nativeTargetType) + val = self.createPointerValue(nativeValue.GetValueAsUnsigned(), targetType) + #warn('CREATED PTR 1: %s' % val) + val.laddress = nativeValue.AddressOf().GetValueAsUnsigned() + #warn('CREATED PTR 2: %s' % val) + return val + if code == lldb.eTypeClassTypedef: + nativeTargetType = nativeType.GetUnqualifiedType() + if hasattr(nativeTargetType, 'GetCanonicalType'): + nativeTargetType = nativeTargetType.GetCanonicalType() + val = self.fromNativeValue(nativeValue.Cast(nativeTargetType)) + val.type = self.fromNativeType(nativeType) + #warn('CREATED TYPEDEF: %s' % val) + return val + val = self.Value(self) + address = nativeValue.GetLoadAddress() + if not address is None: + val.laddress = address + if True: + #val.name = nativeValue.GetName() + data = nativeValue.GetData() + error = lldb.SBError() + size = nativeValue.GetType().GetByteSize() + if size > 1: + # 0 happens regularly e.g. for cross-shared-object types. + # 1 happens on Linux + try: + val.ldata = data.ReadRawData(error, 0, size) + except: + pass + val.type = self.fromNativeType(nativeType) val.lIsInScope = nativeValue.IsInScope() - #val.name = nativeValue.GetName() - data = nativeValue.GetData() - error = lldb.SBError() - size = nativeValue.GetType().GetByteSize() - if size > 0: # Happens regularly e.g. for cross-shared-object types. - val.ldata = data.ReadRawData(error, 0, size) - code = nativeType.GetTypeClass() - if code not in (lldb.eTypeClassPointer, lldb.eTypeClassReference): - val.laddress = int(nativeValue.GetLoadAddress()) + + #if code not in (lldb.eTypeClassPointer, lldb.eTypeClassReference): + # val.laddress = int(nativeValue.GetLoadAddress()) if code == lldb.eTypeClassEnumeration: intval = nativeValue.GetValueAsSigned() if hasattr(nativeType, 'get_enum_members_array'): @@ -137,69 +183,233 @@ class Dumper(DumperBase): if diff & mask == 0: path = nativeType.GetName().split('::') path[-1] = enumMember.GetName() - val.ldisplay = "%s (%d)" % ('::'.join(path), intval) - val.ldisplay = "%d" % intval + val.ldisplay = '%s (%d)' % ('::'.join(path), intval) + val.ldisplay = '%d' % intval elif code in (lldb.eTypeClassComplexInteger, lldb.eTypeClassComplexFloat): val.ldisplay = str(nativeValue.GetValue()) - elif code == lldb.eTypeClassArray: - if hasattr(nativeType, "GetArrayElementType"): # New in 3.8(?) / 350.x - val.type.ltarget = self.fromNativeType(nativeType.GetArrayElementType()) - else: - fields = nativeType.get_fields_array() - if len(fields): - val.type.ltarget = self.fromNativeType(fields[0]) - elif code == lldb.eTypeClassVector: - val.type.ltarget = self.fromNativeType(nativeType.GetVectorElementType()) + elif code == lldb.eTypeClassReference: + #val.laddress = int(nativeValue.GetLoadAddress()) + #val.ldata = None + derefNativeValue = nativeValue.Dereference() + derefNativeValue = derefNativeValue.Cast(derefNativeValue.GetType().GetUnqualifiedType()) + val1 = self.Value(self) + val1.type = val.type + val1.targetValue = self.fromNativeValue(derefNativeValue) + return val1 + #elif code == lldb.eTypeClassArray: + # if hasattr(nativeType, 'GetArrayElementType'): # New in 3.8(?) / 350.x + # val.type.ltarget = self.fromNativeType(nativeType.GetArrayElementType()) + # else: + # fields = nativeType.get_fields_array() + # if len(fields): + # val.type.ltarget = self.fromNativeType(fields[0]) + #elif code == lldb.eTypeClassVector: + # val.type.ltarget = self.fromNativeType(nativeType.GetVectorElementType()) return val - def fromNativeType(self, nativeType): - typeobj = self.Type(self) - if nativeType.IsPointerType(): - typeobj.nativeType = nativeType - else: - # This strips typedefs for pointers. We don't want that. - typeobj.nativeType = nativeType.GetUnqualifiedType() - if hasattr(typeobj.nativeType, "GetDisplayTypeName"): - typeobj.name = typeobj.nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320) - else: - typeobj.name = typeobj.nativeType.GetName() # Xcode 5 (lldb-310) - typeobj.lbitsize = nativeType.GetByteSize() * 8 - code = nativeType.GetTypeClass() - try: - typeobj.code = { - lldb.eTypeClassArray : TypeCodeArray, - lldb.eTypeClassVector : TypeCodeArray, - lldb.eTypeClassComplexInteger : TypeCodeComplex, - lldb.eTypeClassComplexFloat : TypeCodeComplex, - lldb.eTypeClassClass : TypeCodeStruct, - lldb.eTypeClassStruct : TypeCodeStruct, - lldb.eTypeClassUnion : TypeCodeStruct, - lldb.eTypeClassEnumeration : TypeCodeEnum, - lldb.eTypeClassTypedef : TypeCodeTypedef, - lldb.eTypeClassReference : TypeCodeReference, - lldb.eTypeClassPointer : TypeCodePointer, - lldb.eTypeClassFunction : TypeCodeFunction, - lldb.eTypeClassMemberPointer : TypeCodeMemberPointer - }[code] - except KeyError: - if code == lldb.eTypeClassBuiltin: - if isFloatingPointTypeName(typeobj.name): - typeobj.code = TypeCodeFloat - elif isIntegralTypeName(typeobj.name): - typeobj.code = TypeCodeIntegral - else: - warn("UNKNOWN TYPE KEY: %s: %s" % (typeobj.name, code)) - else: - warn("UNKNOWN TYPE KEY: %s: %s" % (typeobj.name, code)) - #warn("CREATE TYPE: %s CODE: %s" % (typeobj.name, typeobj.code)) - return typeobj + def ptrSize(self): + result = self.target.GetAddressByteSize() + self.ptrSize = lambda: result + return result - def nativeTypeFields(self, nativeType): + def fromNativeType(self, nativeType): + self.check(isinstance(nativeType, lldb.SBType)) + code = nativeType.GetTypeClass() + + #warn('CURRENT: %s' % self.typeData.keys()) + #warn('FROM NATIVE TYPE: %s' % nativeType.GetName()) + if code == lldb.eTypeClassInvalid: + return None + + if code == lldb.eTypeClassBuiltin: + nativeType = nativeType.GetUnqualifiedType() + + if code == lldb.eTypeClassPointer: + #warn('PTR') + nativeTargetType = nativeType.GetPointeeType() + if not nativeTargetType.IsPointerType(): + nativeTargetType = nativeTargetType.GetUnqualifiedType() + #warn('PTR: %s' % nativeTargetType.name) + return self.createPointerType(self.fromNativeType(nativeTargetType)) + + if code == lldb.eTypeClassReference: + #warn('REF') + nativeTargetType = nativeType.GetDereferencedType() + if not nativeTargetType.IsPointerType(): + nativeTargetType = nativeTargetType.GetUnqualifiedType() + #warn('REF: %s' % nativeTargetType.name) + return self.createReferenceType(self.fromNativeType(nativeTargetType)) + + if code in (lldb.eTypeClassArray, lldb.eTypeClassVector): + #warn('ARRAY: %s' % nativeType.GetName()) + if hasattr(nativeType, 'GetArrayElementType'): # New in 3.8(?) / 350.x + nativeTargetType = nativeType.GetArrayElementType() + if not nativeTargetType.IsValid(): + if hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x + #warn('BAD: %s ' % nativeTargetType.get_fields_array()) + nativeTargetType = nativeType.GetVectorElementType() + elif hasattr(nativeType, 'GetVectorElementType'): # New in 3.8(?) / 350.x + nativeTargetType = nativeType.GetVectorElementType() + else: + return self.createType(nativeType.GetName()) + + #warn('NATIVE TARGET TYPE: %s' % nativeTargetType) + #warn('NATIVE TARGE NAME: %s' % nativeTargetType.GetName()) + targetType = self.fromNativeType(nativeTargetType) + count = nativeType.GetByteSize() // nativeTargetType.GetByteSize() + return self.createArrayType(targetType, count) + + if code == lldb.eTypeClassTypedef: + #warn('TYPEDEF') + nativeTargetType = nativeType.GetUnqualifiedType() + if hasattr(nativeTargetType, 'GetCanonicalType'): + nativeTargetType = nativeTargetType.GetCanonicalType() + targetType = self.fromNativeType(nativeTargetType) + return self.createTypedefedType(targetType, nativeType.GetName()) + + nativeType = nativeType.GetUnqualifiedType() + typeId = self.nativeTypeId(nativeType) + res = self.typeData.get(typeId, None) + if res is None: + # # This strips typedefs for pointers. We don't want that. + # typeobj.nativeType = nativeType.GetUnqualifiedType() + tdata = self.TypeData(self) + if hasattr(nativeType, 'GetDisplayTypeName'): + tdata.name = nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320) + else: + tdata.name = nativeType.GetName() # Xcode 5 (lldb-310) + tdata.typeId = typeId + tdata.lbitsize = nativeType.GetByteSize() * 8 + if code == lldb.eTypeClassBuiltin: + if isFloatingPointTypeName(tdata.name): + tdata.code = TypeCodeFloat + elif isIntegralTypeName(tdata.name): + tdata.code = TypeCodeIntegral + elif tdata.name == 'void': + tdata.code = TypeCodeVoid + else: + warn('UNKNOWN TYPE KEY: %s: %s' % (tdata.name, code)) + else: + # eTypeClassInvalid = (0u), + # eTypeClassArray = (1u << 0), + # eTypeClassBlockPointer = (1u << 1), + # eTypeClassBuiltin = (1u << 2), + # eTypeClassClass = (1u << 3), + # eTypeClassComplexFloat = (1u << 4), + # eTypeClassComplexInteger = (1u << 5), + # eTypeClassEnumeration = (1u << 6), + # eTypeClassFunction = (1u << 7), + # eTypeClassMemberPointer = (1u << 8), + # eTypeClassObjCObject = (1u << 9), + # eTypeClassObjCInterface = (1u << 10), + # eTypeClassObjCObjectPointer = (1u << 11), + # eTypeClassPointer = (1u << 12), + # eTypeClassReference = (1u << 13), + # eTypeClassStruct = (1u << 14), + # eTypeClassTypedef = (1u << 15), + # eTypeClassUnion = (1u << 16), + # eTypeClassVector = (1u << 17), + # // Define the last type class as the MSBit of a 32 bit value + # eTypeClassOther = (1u << 31), + # // Define a mask that can be used for any type when finding types + # eTypeClassAny = (0xffffffffu) + tdata.code = { + #lldb.eTypeClassArray : TypeCodeArray, + #lldb.eTypeClassVector : TypeCodeArray, + lldb.eTypeClassComplexInteger : TypeCodeComplex, + lldb.eTypeClassComplexFloat : TypeCodeComplex, + lldb.eTypeClassClass : TypeCodeStruct, + lldb.eTypeClassStruct : TypeCodeStruct, + lldb.eTypeClassUnion : TypeCodeStruct, + lldb.eTypeClassEnumeration : TypeCodeEnum, + #lldb.eTypeClassTypedef : TypeCodeTypedef, + #lldb.eTypeClassReference : TypeCodeReference, + #lldb.eTypeClassPointer : TypeCodePointer, + lldb.eTypeClassFunction : TypeCodeFunction, + lldb.eTypeClassMemberPointer : TypeCodeMemberPointer + }[code] + if tdata.code == TypeCodeEnum: + tdata.enumDisplay = lambda intval: self.nativeTypeEnumDisplay(nativeType, intval) + self.registerType(typeId, tdata) # Prevent recursion in fields. + tdata.lfields = self.listFields(nativeType, self.Type(self, typeId)) + tdata.templateArguments = self.listTemplateParametersHelper(nativeType) + self.registerType(typeId, tdata) # Fix up fields and template args + # warn('CREATE TYPE: %s' % typeId) + #else: + # warn('REUSE TYPE: %s' % typeId) + return self.Type(self, typeId) + + def listTemplateParametersHelper(self, nativeType): + stringArgs = self.listTemplateParameters(nativeType.GetName()) + n = nativeType.GetNumberOfTemplateArguments() + if n != len(stringArgs): + # Something wrong in the debug info. + # Should work in theory, doesn't work in practice. + # Items like std::allocator report 0 + # for nativeType.GetNumberOfTemplateArguments() with LLDB 3.8 + return stringArgs + + targs = [] + for i in range(nativeType.GetNumberOfTemplateArguments()): + kind = nativeType.GetTemplateArgumentKind(i) + # eTemplateArgumentKindNull = 0, + # eTemplateArgumentKindType, + # eTemplateArgumentKindDeclaration, + # eTemplateArgumentKindIntegral, + # eTemplateArgumentKindTemplate, + # eTemplateArgumentKindTemplateExpansion, + # eTemplateArgumentKindExpression, + # eTemplateArgumentKindPack + if kind == lldb.eTemplateArgumentKindType: + innerType = nativeType.GetTemplateArgumentType(i).GetUnqualifiedType().GetCanonicalType() + targs.append(self.fromNativeType(innerType)) + #elif kind == lldb.eTemplateArgumentKindIntegral: + # innerType = nativeType.GetTemplateArgumentType(i).GetUnqualifiedType().GetCanonicalType() + # #warn('INNER TYP: %s' % innerType) + # basicType = innerType.GetBasicType() + # #warn('IBASIC TYP: %s' % basicType) + # inner = self.extractTemplateArgument(nativeType.GetName(), i) + # exp = '(%s)%s' % (innerType.GetName(), inner) + # #warn('EXP : %s' % exp) + # val = self.nativeParseAndEvaluate('(%s)%s' % (innerType.GetName(), inner)) + # # Clang writes 'int' and '0xfffffff' into the debug info + # # LLDB manages to read a value of 0xfffffff... + # #if basicType == lldb.eBasicTypeInt: + # value = val.GetValueAsUnsigned() + # if value >= 0x8000000: + # value -= 0x100000000 + # #warn('KIND: %s' % kind) + # targs.append(value) + else: + #warn('UNHANDLED TEMPLATE TYPE : %s' % kind) + targs.append(stringArgs[i]) # Best we can do. + #warn('TARGS: %s %s' % (nativeType.GetName(), [str(x) for x in targs])) + return targs + + def nativeTypeId(self, nativeType): + if hasattr(nativeType, 'GetDisplayTypeName'): + name = nativeType.GetDisplayTypeName() # Xcode 6 (lldb-320) + else: + name = nativeType.GetName() # Xcode 5 (lldb-310) + if name is None or len(name) == 0: + c = '0' + elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassStruct: + c = 's' + elif name == '(anonymous struct)' and nativeType.GetTypeClass() == lldb.eTypeClassUnion: + c = 'u' + else: + return name + fields = nativeType.get_fields_array() + typeId = c + ''.join(['{%s:%s}' % (f.name, self.nativeTypeId(f.GetType())) for f in fields]) + #warn('NATIVE TYPE ID FOR %s IS %s' % (name, typeId)) + return typeId + + def listFields(self, nativeType, parentType): fields = [] if self.currentContextValue is not None: addr = self.currentContextValue.AddressOf().GetValueAsUnsigned() else: - warn("CREATING DUMMY CONTEXT") + warn('CREATING DUMMY CONTEXT') addr = 0 # FIXME: 0 doesn't produce valid member offsets. addr = 0x7fffffffe0a0 sbaddr = lldb.SBAddress(addr, self.target) @@ -226,9 +436,9 @@ class Dumper(DumperBase): f.GetOffsetInBits())) for f in nativeType.get_fields_array()) - #warn("BASE NAMES: %s" % baseNames) - #warn("VIRTUAL NAMES: %s" % virtualNames) - #warn("FIELD BITS: %s" % fieldBits) + #warn('BASE NAMES: %s' % baseNames) + #warn('VIRTUAL NAMES: %s' % virtualNames) + #warn('FIELD BITS: %s' % fieldBits) fieldParentType = self.fromNativeType(nativeType).stripTypedefs() # This does not list empty base entries. @@ -237,10 +447,10 @@ class Dumper(DumperBase): fieldName = dummyChild.GetName() if fieldName is None: anonNumber += 1 - fieldName = "#%s" % anonNumber - fieldType = dummyChild.GetType() - #warn("CHILD AT: %s: %s %s" % (i, fieldName, fieldType.GetName())) - #warn(" AT: %s: %s %s" % (i, fieldName, fieldType.GetName())) + fieldName = '#%s' % anonNumber + fieldType = dummyChild.GetType().GetUnqualifiedType() + #warn('CHILD AT: %s: %s %s' % (i, fieldName, fieldType.GetName())) + #warn(' AT: %s: %s %s' % (i, fieldName, fieldType.GetName())) caddr = dummyChild.AddressOf().GetValueAsUnsigned() child = self.Value(self) child.type = self.fromNativeType(fieldType) @@ -257,12 +467,12 @@ class Dumper(DumperBase): field.lbitsize = fieldType.GetByteSize() * 8 field.lbitpos = (caddr - addr) * 8 if fieldName in baseNames: - #warn("BASE: %s P0S: 0x%x - 0x%x = %s" % (fieldName, caddr, addr, caddr - addr)) + #warn('BASE: %s P0S: 0x%x - 0x%x = %s' % (fieldName, caddr, addr, caddr - addr)) field.isBaseClass = True field.baseIndex = baseNames[fieldName] if fieldName in virtualNames: field.isVirtualBase = True - #warn("ADDING VRITUAL BASE: %s" % fieldName) + #warn('ADDING VIRTUAL BASE: %s' % fieldName) fields.append(field) # Add empty bases. @@ -287,29 +497,10 @@ class Dumper(DumperBase): field.lbitpos = 0 fields.append(field) - #warn("FIELD NAMES: %s" % [field.name for field in fields]) - #warn("FIELDS: %s" % fields) + #warn('FIELD NAMES: %s' % [field.name for field in fields]) + #warn('FIELDS: %s' % fields) return fields - def nativeTypeUnqualified(self, nativeType): - return self.fromNativeType(nativeType.GetUnqualifiedType()) - - def nativeTypePointer(self, nativeType): - return self.fromNativeType(nativeType.GetPointerType()) - - def nativeTypeStripTypedefs(self, typeobj): - if hasattr(typeobj, 'GetCanonicalType'): - return self.fromNativeType(typeobj.GetCanonicalType()) - return self.fromNativeType(typeobj) - - def nativeTypeFirstBase(self, nativeType): - #warn("FIRST BASE FROM: %s" % nativeType) - if nativeType.GetNumberOfDirectBaseClasses() == 0: - return None - t = nativeType.GetDirectBaseClassAtIndex(0) - #warn(" GOT BASE FROM: %s" % t) - return self.fromNativeType(nativeType.GetDirectBaseClassAtIndex(0).GetType()) - def nativeTypeEnumDisplay(self, nativeType, intval): if hasattr(nativeType, 'get_enum_members_array'): for enumMember in nativeType.get_enum_members_array(): @@ -319,8 +510,8 @@ class Dumper(DumperBase): if diff & mask == 0: path = nativeType.GetName().split('::') path[-1] = enumMember.GetName() - return "%s (%d)" % ('::'.join(path), intval) - return "%d" % intval + return '%s (%d)' % ('::'.join(path), intval) + return '%d' % intval def nativeDynamicTypeName(self, address, baseType): return None # FIXME: Seems sufficient, no idea why. @@ -371,18 +562,18 @@ class Dumper(DumperBase): def enumExpression(self, enumType, enumValue): ns = self.qtNamespace() - return ns + "Qt::" + enumType + "(" \ - + ns + "Qt::" + enumType + "::" + enumValue + ")" + return ns + 'Qt::' + enumType + '(' \ + + ns + 'Qt::' + enumType + '::' + enumValue + ')' def callHelper(self, rettype, value, func, args): # args is a tuple. arg = ','.join(args) - #warn("PRECALL: %s -> %s(%s)" % (value.address(), func, arg)) + #warn('PRECALL: %s -> %s(%s)' % (value.address(), func, arg)) typename = value.type.name - exp = "((%s*)0x%x)->%s(%s)" % (typename, value.address(), func, arg) - #warn("CALL: %s" % exp) + exp = '((%s*)0x%x)->%s(%s)' % (typename, value.address(), func, arg) + #warn('CALL: %s' % exp) result = self.currentContextValue.CreateValueFromExpression('', exp) - #warn(" -> %s" % result) + #warn(' -> %s' % result) return self.fromNativeValue(result) def pokeValue(self, typeName, *args): @@ -390,12 +581,12 @@ class Dumper(DumperBase): frame = thread.GetFrameAtIndex(0) inner = ','.join(args) value = frame.EvaluateExpression(typeName + '{' + inner + '}') - #self.warn(" TYPE: %s" % value.type) - #self.warn(" ADDR: 0x%x" % value.address) - #self.warn(" VALUE: %s" % value) + #self.warn(' TYPE: %s' % value.type) + #self.warn(' ADDR: 0x%x' % value.address) + #self.warn(' VALUE: %s' % value) return value - def parseAndEvaluate(self, exp): + def nativeParseAndEvaluate(self, exp): thread = self.currentThread() frame = thread.GetFrameAtIndex(0) val = frame.EvaluateExpression(exp) @@ -403,51 +594,15 @@ class Dumper(DumperBase): #val = self.target.EvaluateExpression(exp, options) err = val.GetError() if err.Fail(): - #warn("FAILING TO EVAL: %s" % exp) + #warn('FAILING TO EVAL: %s' % exp) return None - #warn("NO ERROR.") - #warn("EVAL: %s -> %s" % (exp, val.IsValid())) - return self.fromNativeValue(val) + #warn('NO ERROR.') + #warn('EVAL: %s -> %s' % (exp, val.IsValid())) + return val - def nativeTypeTemplateArgument(self, nativeType, position, numeric = False): - if numeric: - # There seems no API to extract the numeric value. - inner = self.extractTemplateArgument(nativeType.GetName(), position) - innerType = nativeType.GetTemplateArgumentType(position) - basicType = innerType.GetBasicType() - value = toInteger(inner) - # Clang writes 'int' and '0xfffffff' into the debug info - # LLDB manages to read a value of 0xfffffff... - if basicType == lldb.eBasicTypeInt and value >= 0x8000000: - value -= 0x100000000 - return value - else: - #warn("nativeTypeTemplateArgument: %s: pos %s" % (nativeType, position)) - typeobj = nativeType.GetTemplateArgumentType(position).GetUnqualifiedType() - if typeobj.IsValid(): - # warn("TYPE: %s" % typeobj) - return self.fromNativeType(typeobj) - inner = self.extractTemplateArgument(nativeType.GetName(), position) - #warn("INNER: %s" % inner) - return self.lookupType(inner) - - def nativeTypeDereference(self, nativeType): - return self.fromNativeType(nativeType.GetPointeeType()) - - def nativeTypeTarget(self, nativeType): - code = nativeType.GetTypeClass() - if code == lldb.eTypeClassPointer: - return self.fromNativeType(nativeType.GetPointeeType()) - if code == lldb.eTypeClassReference: - return self.fromNativeType(nativeType.GetDereferencedType()) - if code == lldb.eTypeClassArray: - if hasattr(nativeType, "GetArrayElementType"): # New in 3.8(?) / 350.x - return self.fromNativeType(nativeType.GetArrayElementType()) - fields = nativeType.get_fields_array() - return None if not len(fields) else self.nativeTypeTarget(fields[0]) - if code == lldb.eTypeClassVector: - return self.fromNativeType(nativeType.GetVectorElementType()) - return self.fromNativeType(nativeType) + def parseAndEvaluate(self, exp): + val = self.nativeParseAndEvaluate(exp) + return None if val is None else self.fromNativeValue(val) def isWindowsTarget(self): return False @@ -524,41 +679,70 @@ class Dumper(DumperBase): return re.sub('\\bconst\\b', '', name).replace(' ', '') def lookupNativeType(self, name): - #warn("LOOKUP TYPE NAME: %s" % name) + #warn('LOOKUP TYPE NAME: %s' % name) + typeobj = self.typeCache.get(name) + if not typeobj is None: + #warn('CACHED: %s' % name) + return typeobj typeobj = self.target.FindFirstType(name) if typeobj.IsValid(): - #warn("VALID FIRST : %s" % dir(typeobj)) + #warn('VALID FIRST : %s' % typeobj) + self.typeCache[name] = typeobj return typeobj - typeobj = self.target.FindFirstType(name + '*') - if typeobj.IsValid(): - return typeob.GetPointeeType() - typeobj = self.target.FindFirstType(name + '&') - if typeobj.IsValid(): - return typeob.GetReferencedType() if name.endswith('*'): - typeobj = self.target.FindFirstType(name[:-1].strip()) - if typeobj.IsValid(): + #warn('RECURSE PTR') + typeobj = self.lookupNativeType(name[:-1].strip()) + if typeobj is not None: + #warn('RECURSE RESULT X: %s' % typeobj) + self.fromNativeType(typeobj.GetPointerType()) + #warn('RECURSE RESULT: %s' % typeobj.GetPointerType()) return typeobj.GetPointerType() - #warn("LOOKUP RESULT: %s" % typeobj.name) - #warn("LOOKUP VALID: %s" % typeobj.IsValid()) + + #typeobj = self.target.FindFirstType(name[:-1].strip()) + #if typeobj.IsValid(): + # self.typeCache[name] = typeobj.GetPointerType() + # return typeobj.GetPointerType() + + if name.endswith(' const'): + #warn('LOOKUP END CONST') + typeobj = self.lookupNativeType(name[:-6]) + if typeobj is not None: + return typeobj + + if name.startswith('const '): + #warn('LOOKUP START CONST') + typeobj = self.lookupNativeType(name[6:]) + if typeobj is not None: + return typeobj + needle = self.canonicalTypeName(name) - #self.warn("NEEDLE: %s " % needle) + #warn('NEEDLE: %s ' % needle) for i in xrange(self.target.GetNumModules()): module = self.target.GetModuleAtIndex(i) # SBModule.GetType is new somewhere after early 300.x # So this may fail. for t in module.GetTypes(): n = self.canonicalTypeName(t.GetName()) + #warn('N: %s' % n) if n == needle: - #self.warn("FOUND TYPE DIRECT 2: %s " % t) + #warn('FOUND TYPE DIRECT 2: %s ' % t) + self.typeCache[name] = t return t if n == needle + '*': - #self.warn("FOUND TYPE BY POINTER 2: %s " % t.GetPointeeType()) - return t.GetPointeeType() + res = t.GetPointeeType() + self.typeCache[name] = res + x = self.fromNativeType(res) # Register under both names + self.registerTypeAlias(x.typeId, name) + #warn('FOUND TYPE BY POINTER: %s ' % res.name) + return res if n == needle + '&': - #self.warn("FOUND TYPE BY REFERENCE 2: %s " % t) - return t.GetDereferencedType() - #warn("NOT FOUND: %s " % needle) + res = t.GetDereferencedType().GetUnqualifiedType() + self.typeCache[name] = res + x = self.fromNativeType(res) # Register under both names + self.registerTypeAlias(x.typeId, name) + #warn('FOUND TYPE BY REFERENCE: %s ' % res.name) + return res + #warn('NOT FOUND: %s ' % needle) return None def setupInferior(self, args): @@ -584,7 +768,7 @@ class Dumper(DumperBase): self.ignoreStops = 0 self.silentStops = 0 - if platform.system() == "Linux": + if platform.system() == 'Linux': if self.startMode_ == AttachCore: pass else: @@ -610,7 +794,7 @@ class Dumper(DumperBase): if self.nativeMixed: self.interpreterEventBreakpoint = \ - self.target.BreakpointCreateByName("qt_qmlDebugMessageAvailable") + self.target.BreakpointCreateByName('qt_qmlDebugMessageAvailable') state = 1 if self.target.IsValid() else 0 self.reportResult('success="%s",msg="%s",exe="%s"' @@ -632,7 +816,7 @@ class Dumper(DumperBase): attachInfo = lldb.SBAttachInfo(self.attachPid_) self.process = self.target.Attach(attachInfo, error) if not error.Success(): - self.reportState("inferiorrunfailed") + self.reportState('inferiorrunfailed') return self.report('pid="%s"' % self.process.GetProcessID()) # Even if it stops it seems that LLDB assumes it is running @@ -641,29 +825,29 @@ class Dumper(DumperBase): if self.process and self.process.GetState() == lldb.eStateStopped: # lldb stops the process after attaching. This happens before the # eventloop starts. Relay the correct state back. - self.reportState("enginerunandinferiorstopok") + self.reportState('enginerunandinferiorstopok') else: - self.reportState("enginerunandinferiorrunok") + self.reportState('enginerunandinferiorrunok') elif self.startMode_ == AttachToRemoteServer or self.startMode_ == AttachToRemoteProcess: self.process = self.target.ConnectRemote( self.debugger.GetListener(), self.remoteChannel_, None, error) if not error.Success(): self.report(self.describeError(error)) - self.reportState("enginerunfailed") + self.reportState('enginerunfailed') return # Even if it stops it seems that LLDB assumes it is running # and later detects that it did stop after all, so it is be # better to mirror that and wait for the spontaneous stop. - self.reportState("enginerunandinferiorrunok") + self.reportState('enginerunandinferiorrunok') elif self.startMode_ == AttachCore: coreFile = args.get('coreFile', ''); self.process = self.target.LoadCore(coreFile) - self.reportState("enginerunokandinferiorunrunnable") + self.reportState('enginerunokandinferiorunrunnable') else: launchInfo = lldb.SBLaunchInfo(self.processArgs_) launchInfo.SetWorkingDirectory(self.workingDirectory_) - environmentList = [key + "=" + value for key,value in os.environ.items()] + environmentList = [key + '=' + value for key,value in os.environ.items()] if self.dyldImageSuffix: environmentList.append('DYLD_IMAGE_SUFFIX=' + self.dyldImageSuffix) if self.dyldLibraryPath: @@ -676,10 +860,10 @@ class Dumper(DumperBase): self.process = self.target.Launch(launchInfo, error) if not error.Success(): self.report(self.describeError(error)) - self.reportState("enginerunfailed") + self.reportState('enginerunfailed') return self.report('pid="%s"' % self.process.GetProcessID()) - self.reportState("enginerunandinferiorrunok") + self.reportState('enginerunandinferiorrunok') def loop(self): event = lldb.SBEvent() @@ -737,11 +921,11 @@ class Dumper(DumperBase): for i in xrange(0, self.process.GetNumThreads()): thread = self.process.GetThreadAtIndex(i) if thread.is_stopped: - state = "stopped" + state = 'stopped' elif thread.is_suspended: - state = "suspended" + state = 'suspended' else: - state = "unknown" + state = 'unknown' reason = thread.GetStopReason() result += '{id="%d"' % thread.GetThreadID() result += ',index="%s"' % i @@ -803,7 +987,7 @@ class Dumper(DumperBase): functionName = frame.GetFunctionName() - if isNativeMixed and functionName == "::qt_qmlDebugMessageAvailable()": + if isNativeMixed and functionName == '::qt_qmlDebugMessageAvailable()': interpreterStack = self.extractInterpreterStack() for interpreterFrame in interpreterStack.get('frames', []): function = interpreterFrame.get('function', '') @@ -843,8 +1027,9 @@ class Dumper(DumperBase): error = lldb.SBError() #warn("READ: %s %s" % (address, size)) res = self.process.ReadMemory(address, size, error) - if res is None: - return bytes() + if res is None or len(res) != size: + # Using code in e.g. readToFirstZero relies on exceptions. + raise RuntimeError("Unreadable %s bytes at 0x%x" % (size, address)) return res def findStaticMetaObject(self, typeName): @@ -919,7 +1104,7 @@ class Dumper(DumperBase): # This can happen for unnamed function parameters with # default values: void foo(int = 0) continue - value = self.fromNativeValue(val) + value = self.fromNativeFrameValue(val) value.name = name variables.append(value) @@ -1120,13 +1305,13 @@ class Dumper(DumperBase): def createBreakpointAtMain(self): return self.target.BreakpointCreateByName( - "main", self.target.GetExecutable().GetFilename()) + 'main', self.target.GetExecutable().GetFilename()) def insertBreakpoint(self, args): - bpType = args["type"] + bpType = args['type'] if bpType == BreakpointByFileAndLine: - fileName = args["file"] - if fileName.endswith(".js") or fileName.endswith(".qml"): + fileName = args['file'] + if fileName.endswith('.js') or fileName.endswith('.qml'): self.insertInterpreterBreakpoint(args) return @@ -1134,11 +1319,11 @@ class Dumper(DumperBase): more = True if bpType == BreakpointByFileAndLine: bp = self.target.BreakpointCreateByLocation( - str(args["file"]), int(args["line"])) + str(args['file']), int(args['line'])) elif bpType == BreakpointByFunction: - bp = self.target.BreakpointCreateByName(args["function"]) + bp = self.target.BreakpointCreateByName(args['function']) elif bpType == BreakpointByAddress: - bp = self.target.BreakpointCreateByAddress(args["address"]) + bp = self.target.BreakpointCreateByAddress(args['address']) elif bpType == BreakpointAtMain: bp = self.createBreakpointAtMain() elif bpType == BreakpointAtThrow: @@ -1150,14 +1335,14 @@ class Dumper(DumperBase): elif bpType == WatchpointAtAddress: error = lldb.SBError() # This might yield bp.IsValid() == False and - # error.desc == "process is not alive". - bp = self.target.WatchAddress(args["address"], 4, False, True, error) + # error.desc == 'process is not alive'. + bp = self.target.WatchAddress(args['address'], 4, False, True, error) extra = self.describeError(error) elif bpType == WatchpointAtExpression: # FIXME: Top level-only for now. try: frame = self.currentFrame() - value = frame.FindVariable(args["expression"]) + value = frame.FindVariable(args['expression']) error = lldb.SBError() bp = self.target.WatchAddress(value.GetLoadAddress(), value.GetByteSize(), False, True, error) @@ -1165,45 +1350,45 @@ class Dumper(DumperBase): bp = self.target.BreakpointCreateByName(None) else: # This leaves the unhandled breakpoint in a (harmless) - # "pending" state. + # 'pending' state. bp = self.target.BreakpointCreateByName(None) more = False if more and bp.IsValid(): - bp.SetIgnoreCount(int(args["ignorecount"])) - bp.SetCondition(self.hexdecode(args["condition"])) - bp.SetEnabled(bool(args["enabled"])) + bp.SetIgnoreCount(int(args['ignorecount'])) + bp.SetCondition(self.hexdecode(args['condition'])) + bp.SetEnabled(bool(args['enabled'])) bp.SetScriptCallbackBody('\n'.join([ - "def foo(frame = frame, bp_loc = bp_loc, dict = internal_dict):", - " " + self.hexdecode(args["command"]).replace('\n', '\n '), - "from cStringIO import StringIO", - "origout = sys.stdout", - "sys.stdout = StringIO()", - "result = foo()", - "d = lldb.theDumper", - "output = d.hexencode(sys.stdout.getvalue())", - "sys.stdout = origout", - "d.report('output={channel=\"stderr\",data=\"' + output + '\"}')", - "if result is False:", - " d.reportState('continueafternextstop')", - "return True" + 'def foo(frame = frame, bp_loc = bp_loc, dict = internal_dict):', + ' ' + self.hexdecode(args['command']).replace('\n', '\n '), + 'from cStringIO import StringIO', + 'origout = sys.stdout', + 'sys.stdout = StringIO()', + 'result = foo()', + 'd = lldb.theDumper', + 'output = d.hexencode(sys.stdout.getvalue())', + 'sys.stdout = origout', + 'd.report("output={channel=\"stderr\",data=\"' + output + '\"}")', + 'if result is False:', + ' d.reportState("continueafternextstop")', + 'return True' ])) if isinstance(bp, lldb.SBBreakpoint): - bp.SetOneShot(bool(args["oneshot"])) + bp.SetOneShot(bool(args['oneshot'])) self.reportResult(self.describeBreakpoint(bp) + extra, args) def changeBreakpoint(self, args): - lldbId = int(args["lldbid"]) + lldbId = int(args['lldbid']) if lldbId > qqWatchpointOffset: bp = self.target.FindWatchpointByID(lldbId) else: bp = self.target.FindBreakpointByID(lldbId) if bp.IsValid(): - bp.SetIgnoreCount(int(args["ignorecount"])) - bp.SetCondition(self.hexdecode(args["condition"])) - bp.SetEnabled(bool(args["enabled"])) + bp.SetIgnoreCount(int(args['ignorecount'])) + bp.SetCondition(self.hexdecode(args['condition'])) + bp.SetEnabled(bool(args['enabled'])) if isinstance(bp, lldb.SBBreakpoint): - bp.SetOneShot(bool(args["oneshot"])) + bp.SetOneShot(bool(args['oneshot'])) self.reportResult(self.describeBreakpoint(bp), args) def removeBreakpoint(self, args): @@ -1269,16 +1454,16 @@ class Dumper(DumperBase): def shutdownInferior(self, args): self.isShuttingDown_ = True if self.process is None: - self.reportState("inferiorshutdownok") + self.reportState('inferiorshutdownok') else: state = self.process.GetState() if state == lldb.eStateStopped: self.process.Kill() - self.reportState("inferiorshutdownok") + self.reportState('inferiorshutdownok') self.reportResult('', args) def quit(self, args): - self.reportState("engineshutdownok") + self.reportState('engineshutdownok') self.process.Kill() self.reportResult('', args) @@ -1299,7 +1484,7 @@ class Dumper(DumperBase): bp = self.target.BreakpointCreateByAddress(addr) if bp.GetNumLocations() == 0: self.target.BreakpointDelete(bp.GetID()) - self.reportResult(self.describeStatus("No target location found.") + self.reportResult(self.describeStatus('No target location found.') + self.describeLocation(frame), args) return bp.SetOneShot(True) @@ -1311,14 +1496,14 @@ class Dumper(DumperBase): line = int(args['line']) error = self.currentThread().StepOverUntil(frame, lldb.SBFileSpec(file), line) self.reportResult(self.describeError(error), args) - self.reportState("running") - self.reportState("stopped") + self.reportState('running') + self.reportState('stopped') def executeJumpToLocation(self, args): self.reportToken(args) frame = self.currentFrame() if not frame: - self.reportResult(self.describeStatus("No frame available."), args) + self.reportResult(self.describeStatus('No frame available.'), args) return addr = args.get('address', 0) if addr: @@ -1328,17 +1513,17 @@ class Dumper(DumperBase): str(args['file']), int(args['line'])) if bp.GetNumLocations() == 0: self.target.BreakpointDelete(bp.GetID()) - status = "No target location found." + status = 'No target location found.' else: loc = bp.GetLocationAtIndex(0) self.target.BreakpointDelete(bp.GetID()) res = frame.SetPC(loc.GetLoadAddress()) - status = "Jumped." if res else "Cannot jump." + status = 'Jumped.' if res else 'Cannot jump.' self.reportResult(self.describeStatus(status) + self.describeLocation(frame), args) def breakList(self): result = lldb.SBCommandReturnObject() - self.debugger.GetCommandInterpreter().HandleCommand("break list", result) + self.debugger.GetCommandInterpreter().HandleCommand('break list', result) self.report('success="%d",output="%s",error="%s"' % (result.Succeeded(), result.GetOutput(), result.GetError())) @@ -1354,7 +1539,7 @@ class Dumper(DumperBase): self.reportResult('', args) def fetchFullBacktrace(self, _ = None): - command = "thread backtrace all" + command = 'thread backtrace all' result = lldb.SBCommandReturnObject() self.debugger.GetCommandInterpreter().HandleCommand(command, result) self.reportResult(self.hexencode(result.GetOutput()), {}) @@ -1385,7 +1570,7 @@ class Dumper(DumperBase): else: base = args.get('address', 0) if int(base) == 0xffffffffffffffff: - warn("INVALID DISASSEMBLER BASE") + warn('INVALID DISASSEMBLER BASE') return addr = lldb.SBAddress(base, self.target) instructions = self.target.ReadInstructions(addr, 100) @@ -1406,7 +1591,7 @@ class Dumper(DumperBase): if lineNumber != currentLine or fileName != currentFile: currentLine = lineNumber currentFile = fileName - key = "%s:%s" % (fileName, lineNumber) + key = '%s:%s' % (fileName, lineNumber) hunk = hunks.get(key, 0) + 1 hunks[key] = hunk source = sources.get(fileName, None) @@ -1419,8 +1604,8 @@ class Dumper(DumperBase): # With lldb-3.8 files like /data/dev/creator-3.6/tests/ # auto/debugger/qt_tst_dumpers_StdVector_bfNWZa/main.cpp # with non-existent directories appear. - warn("FILE: %s ERROR: %s" % (fileName, error)) - source = "" + warn('FILE: %s ERROR: %s' % (fileName, error)) + source = '' result += '{line="%s"' % lineNumber result += ',file="%s"' % fileName if 0 < lineNumber and lineNumber <= len(source): @@ -1463,7 +1648,7 @@ class Dumper(DumperBase): self.reportResult(self.describeError(error), args) def createResolvePendingBreakpointsHookBreakpoint(self, args): - bp = self.target.BreakpointCreateByName("qt_qmlDebugConnectorOpen") + bp = self.target.BreakpointCreateByName('qt_qmlDebugConnectorOpen') bp.SetOneShot(True) self.interpreterBreakpointResolvers.append( lambda: self.resolvePendingInterpreterBreakpoint(args)) @@ -1479,7 +1664,7 @@ class Tester(Dumper): self.target = self.debugger.CreateTarget(binary, None, None, True, error) if error.GetType(): - warn("ERROR: %s" % error) + warn('ERROR: %s' % error) return s = threading.Thread(target=self.testLoop, args=(args,)) @@ -1494,19 +1679,19 @@ class Tester(Dumper): error = lldb.SBError() launchInfo = lldb.SBLaunchInfo([]) launchInfo.SetWorkingDirectory(os.getcwd()) - environmentList = [key + "=" + value for key,value in os.environ.items()] + environmentList = [key + '=' + value for key,value in os.environ.items()] launchInfo.SetEnvironmentEntries(environmentList, False) self.process = self.target.Launch(launchInfo, error) if error.GetType(): - warn("ERROR: %s" % error) + warn('ERROR: %s' % error) event = lldb.SBEvent() listener = self.debugger.GetListener() while True: state = self.process.GetState() if listener.WaitForEvent(100, event): - #warn("EVENT: %s" % event) + #warn('EVENT: %s' % event) state = lldb.SBProcess.GetStateFromEvent(event) if state == lldb.eStateExited: # 10 break @@ -1515,14 +1700,14 @@ class Tester(Dumper): for i in xrange(0, self.process.GetNumThreads()): thread = self.process.GetThreadAtIndex(i) reason = thread.GetStopReason() - #warn("THREAD: %s REASON: %s" % (thread, reason)) + #warn('THREAD: %s REASON: %s' % (thread, reason)) if (reason == lldb.eStopReasonBreakpoint or reason == lldb.eStopReasonException or reason == lldb.eStopReasonSignal): stoppedThread = thread if stoppedThread: - # This seems highly fragile and depending on the "No-ops" in the + # This seems highly fragile and depending on the 'No-ops' in the # event handling above. frame = stoppedThread.GetFrameAtIndex(0) line = frame.line_entry.line @@ -1531,13 +1716,13 @@ class Tester(Dumper): self.process.SetSelectedThread(stoppedThread) self.fetchVariables(args) #self.describeLocation(frame) - self.report("@NS@%s@" % self.qtNamespace()) - #self.report("ENV=%s" % os.environ.items()) - #self.report("DUMPER=%s" % self.qqDumpers) + self.report('@NS@%s@' % self.qtNamespace()) + #self.report('ENV=%s' % os.environ.items()) + #self.report('DUMPER=%s' % self.qqDumpers) break else: warn('TIMEOUT') - warn("Cannot determined stopped thread") + warn('Cannot determined stopped thread') lldb.SBDebugger.Destroy(self.debugger) diff --git a/share/qtcreator/debugger/misctypes.py b/share/qtcreator/debugger/misctypes.py index 29f46c82ee7..54af7e6414c 100644 --- a/share/qtcreator/debugger/misctypes.py +++ b/share/qtcreator/debugger/misctypes.py @@ -121,7 +121,7 @@ def qdump__Eigen__Matrix(d, value): storage = value['m_storage'] nrows = storage['m_rows'].integer() if argRow == -1 else argRow ncols = storage['m_cols'].integer() if argCol == -1 else argCol - p = storage['m_data'].integer() + p = storage['m_data'].pointer() innerSize = innerType.size() d.putValue('(%s x %s), %s' % (nrows, ncols, ['ColumnMajor', 'RowMajor'][rowMajor])) d.putField('keeporder', '1') diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 6e8cb59892e..bb53b4af826 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -152,7 +152,7 @@ def qdump_X_QModelIndex(d, value): except: p = value['i'] m = value['m'] - if m.integer() == 0 or r < 0 or c < 0: + if m.pointer() == 0 or r < 0 or c < 0: d.putValue('(invalid)') d.putPlainChildren(value) return @@ -196,7 +196,7 @@ def qdump_X_QModelIndex(d, value): def qdump__QDate(d, value): - jd = value.integer() + jd = value.pointer() if jd: d.putValue(jd, 'juliandate') d.putNumChild(1) @@ -332,6 +332,7 @@ def qdump__QDateTime(d, value): d.putNumChild(0) return + d.putNumChild(1) if d.isExpanded(): with Children(d): ns = d.qtNamespace() @@ -1120,7 +1121,7 @@ def qdump__QRegion(d, value): def qdump__QScopedPointer(d, value): - if value.integer() == 0: + if value.pointer() == 0: d.putValue('(null)') d.putNumChild(0) else: @@ -1187,13 +1188,13 @@ def qdump__QSet(d, value): def qdump__QSharedData(d, value): - d.putValue('ref: %s' % d.extractInt(value['ref'].address)) + d.putValue('ref: %s' % value.to('i')) d.putNumChild(0) def qdump__QSharedDataPointer(d, value): d_ptr = value['d'] - if d_ptr.integer() == 0: + if d_ptr.pointer() == 0: d.putValue('(null)') d.putNumChild(0) else: @@ -1206,7 +1207,7 @@ def qdump__QSharedDataPointer(d, value): d.putPlainChildren(value) return d.putBetterType(d.currentType) - d.putItem(d_ptr.cast(innerType.pointer()).dereference()) + d.putItem(d_ptr.dereference()) @@ -1404,6 +1405,7 @@ def qdump__QUrl(d, value): if displayFormat == SeparateFormat: d.putDisplay('utf16:separate', url) + d.putNumChild(1) if d.isExpanded(): with Children(d): d.putIntItem('port', port) @@ -1684,12 +1686,12 @@ def qdump__QVariant(d, value): ptr = p.pointer() (elided, blob) = d.encodeCArray(ptr, 1, 100) typeName = d.hexdecode(blob) - base = data.extractPointer() # Prefer namespaced version. if len(ns) > 0: if not d.lookupNativeType(ns + typeName) is None: typeName = ns + typeName - d.putSubItem('data', d.createValue(base, d.createType(typeName))) + data.type = d.createType(typeName + ' *') + d.putSubItem('data', data) if not typeName is None: d.putBetterType('%sQVariant (%s)' % (ns, typeName)) return None @@ -1706,7 +1708,7 @@ def qedit__QVector(d, value, data): base = value['d'].address() + offset except: # Qt 4. - base = value['p']['array'].integer() + base = value['p']['array'].pointer() d.setValues(base, innerType, values) @@ -1766,6 +1768,7 @@ def qdump_QWeakPointerHelper(d, value, isWeak): def qdump__QXmlAttributes__Attribute(d, value): d.putEmptyValue() + d.putNumChild(1) if d.isExpanded(): with Children(d): (qname, uri, localname, val) = value.split('{QString}' * 4) @@ -2345,7 +2348,7 @@ def qdump__QScriptValue(d, value): #d.putEmptyValue() dd = value['d_ptr']['d'] ns = d.qtNamespace() - if dd.integer() == 0: + if dd.pointer() == 0: d.putValue('(invalid)') d.putNumChild(0) return @@ -2621,9 +2624,9 @@ def qdump__QJsonValue(d, value): def qdump__QJsonArray(d, value): - qdumpHelper_QJsonArray(d, value['d'].integer(), value['a'].integer()) + qdumpHelper_QJsonArray(d, value['d'].pointer(), value['a'].pointer()) def qdump__QJsonObject(d, value): - qdumpHelper_QJsonObject(d, value['d'].integer(), value['o'].integer()) + qdumpHelper_QJsonObject(d, value['d'].pointer(), value['o'].pointer()) diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index 2733253bf45..4c8c2cb7545 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -76,17 +76,17 @@ def qdump__std__deque(d, value): impl = value["_M_impl"] start = impl["_M_start"] finish = impl["_M_finish"] - size = bufsize * int((finish["_M_node"].integer() - start["_M_node"].integer()) / d.ptrSize() - 1) - size += int((finish["_M_cur"].integer() - finish["_M_first"].integer()) / innerSize) - size += int((start["_M_last"].integer() - start["_M_cur"].integer()) / innerSize) + size = bufsize * ((finish["_M_node"].pointer() - start["_M_node"].pointer()) // d.ptrSize() - 1) + size += ((finish["_M_cur"].pointer() - finish["_M_first"].pointer()) // innerSize) + size += ((start["_M_last"].pointer() - start["_M_cur"].pointer()) // innerSize) d.check(0 <= size and size <= 1000 * 1000 * 1000) d.putItemCount(size) if d.isExpanded(): with Children(d, size, maxNumChild=2000, childType=innerType): - pcur = start["_M_cur"].integer() + pcur = start["_M_cur"].pointer() pfirst = start["_M_first"] - plast = start["_M_last"].integer() + plast = start["_M_last"].pointer() pnode = start["_M_node"] for i in d.childRange(): d.putSubItem(i, d.createValue(pcur, innerType)) @@ -99,7 +99,7 @@ def qdump__std__deque(d, value): #warn("NEWNODE: 0x%x %s" % (newnode.pointer(), newnode)) pnode = newnode #warn("PNODE 2: 0x%x %s" % (pnode.pointer(), pnode)) - pfirst = newnode.dereference().integer() + pfirst = newnode.dereference().pointer() plast = pfirst + bufsize * d.ptrSize() pcur = pfirst @@ -237,7 +237,6 @@ def qdump__std__map(d, value): if d.isExpanded(): pairType = value.type[3][0] - pairPointer = pairType.pointer() with PairedChildren(d, size, pairType=pairType, maxNumChild=1000): node = value["_M_t"]["_M_impl"]["_M_header"]["_M_left"] nodeSize = node.dereference().type.size() @@ -245,10 +244,10 @@ def qdump__std__map(d, value): for i in d.childRange(): (pad1, key, pad2, value) = d.split(typeCode, node.pointer() + nodeSize) d.putPairItem(i, (key, value)) - if node["_M_right"].integer() == 0: + if node["_M_right"].pointer() == 0: parent = node["_M_parent"] while True: - if node.integer() != parent["_M_right"].integer(): + if node.pointer() != parent["_M_right"].pointer(): break node = parent parent = parent["_M_parent"] @@ -257,7 +256,7 @@ def qdump__std__map(d, value): else: node = node["_M_right"] while True: - if node["_M_left"].integer() == 0: + if node["_M_left"].pointer() == 0: break node = node["_M_left"] @@ -271,13 +270,13 @@ def qdump_std__map__helper(d, size, value): for i in d.childRange(): pair = node.cast(nodeType).dereference()['_Myval'] d.putPairItem(i, pair) - if node['_Right']['_Isnil'].integer() == 0: + if node['_Right']['_Isnil'].pointer() == 0: node = node['_Right'] - while node['_Left']['_Isnil'].integer() == 0: + while node['_Left']['_Isnil'].pointer() == 0: node = node['_Left'] else: parent = node['_Parent'] - while node and parent['_Right']['_Isnil'].integer() == 0: + while node and parent['_Right']['_Isnil'].pointer() == 0: node = parent parent = parent['_Parent'] if node['_Right'] != parent: @@ -377,7 +376,7 @@ def qdump__std__set(d, value): for i in d.childRange(): (pad, val) = d.split(typeCode, node.pointer() + nodeSize) d.putSubItem(i, val) - if node["_M_right"].integer() == 0: + if node["_M_right"].pointer() == 0: parent = node["_M_parent"] while node == parent["_M_right"]: node = parent @@ -386,7 +385,7 @@ def qdump__std__set(d, value): node = parent else: node = node["_M_right"] - while node["_M_left"].integer() != 0: + while node["_M_left"].pointer() != 0: node = node["_M_left"] def qdump__std__set__QNX(d, value): @@ -419,7 +418,7 @@ def std1TreeMin(d, node): # return __x; # left = node['__left_'] - if left.integer(): + if left.pointer(): node = left return node @@ -428,7 +427,7 @@ def std1TreeIsLeftChild(d, node): # return __x == __x->__parent_->__left_; # other = node['__parent_']['__left_'] - return node.integer() == other.integer() + return node.pointer() == other.pointer() def std1TreeNext(d, node): @@ -440,7 +439,7 @@ def std1TreeNext(d, node): # return __x->__parent_; # right = node['__right_'] - if right.integer(): + if right.pointer(): return std1TreeMin(d, right) while not std1TreeIsLeftChild(d, node): node = node['__parent_'] @@ -612,18 +611,18 @@ def qdump__std____1__wstring(d, value): def qdump__std__shared_ptr(d, value): - if d.isMsvcTarget: + if d.isMsvcTarget(): i = value["_Ptr"] else: i = value["_M_ptr"] - if i.integer() == 0: + if i.pointer() == 0: d.putValue("(null)") d.putNumChild(0) return with Children(d): - short = d.putSubItem("data", i) - if d.isMsvcTarget: + short = d.putSubItem("data", i.dereference()) + if d.isMsvcTarget(): refcount = value["_Rep"] d.putIntItem("usecount", refcount["_Uses"]) d.putIntItem("weakcount", refcount["_Weaks"]) @@ -635,7 +634,7 @@ def qdump__std__shared_ptr(d, value): def qdump__std____1__shared_ptr(d, value): i = value["__ptr_"] - if i.integer() == 0: + if i.pointer() == 0: d.putValue("(null)") d.putNumChild(0) return @@ -733,7 +732,7 @@ def qdump__std__unordered_set(d, value): d.putItemCount(size) if d.isExpanded(): - p = start.integer() + p = start.pointer() valueType = value.type[0] with Children(d, size, childType=valueType): ptrSize = d.ptrSize() @@ -974,10 +973,10 @@ def qdump____gnu_cxx__hash_set(d, value): bucketFinish = buckets["_M_finish"] p = bucketStart itemCount = 0 - for i in xrange(int((bucketFinish.integer() - bucketStart.integer()) / d.ptrSize())): - if p.dereference().integer(): + for i in xrange((bucketFinish.pointer() - bucketStart.pointer()) // d.ptrSize()): + if p.dereference().pointer(): cur = p.dereference() - while cur.integer(): + while cur.pointer(): d.putSubItem(itemCount, cur["_M_val"]) cur = cur["_M_next"] itemCount += 1 diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index ee4e556094a..d9f3ac2bd55 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -1903,9 +1903,9 @@ void tst_Dumpers::dumper_data() + Check("h1.2.value.1", "[1]", "2", "int") + Check("h2", "<3 items>", "@QHash") - + Check("h2.0", "[0] 0", FloatValue("33"), "float") - + Check("h2.1", "[1] 22", FloatValue("22"), "float") - + Check("h2.2", "[2] 11", FloatValue("11"), "float") + + Check("h2.0", "[0] 0", FloatValue("33"), "") + + Check("h2.1", "[1] 22", FloatValue("22"), "") + + Check("h2.2", "[2] 11", FloatValue("11"), "") + Check("h3", "<1 items>", "@QHash<@QString, int>") + Check("h3.0.key", "key", "\"22.0\"", "@QString") @@ -1934,7 +1934,7 @@ void tst_Dumpers::dumper_data() + CheckType("h7.2.value", "@QPointer<@QObject>") + Check("h8", "<3 items>", "Hash") - + Check("h8.0", "[0] 22", FloatValue("22"), "float") + + Check("h8.0", "[0] 22", FloatValue("22"), "") + Check("it1.key", "22", "int") + Check("it1.value", FloatValue("22"), "float") + Check("it3.key", "33", "int") @@ -2347,8 +2347,8 @@ void tst_Dumpers::dumper_data() + Check("m1.1.value.0", "[0]", "\"22\"", "@QString") + Check("m2", "<2 items>", "@QMap") - + Check("m2.0", "[0] 11", FloatValue("31.0"), "float") - + Check("m2.1", "[1] 22", FloatValue("32.0"), "float") + + Check("m2.0", "[0] 11", FloatValue("31.0"), "") + + Check("m2.1", "[1] 22", FloatValue("32.0"), "") + Check("m3", "<2 items>", "T") @@ -2432,8 +2432,8 @@ void tst_Dumpers::dumper_data() + Check("m0", "<0 items>", "@QMultiMap") + Check("m1", "<6 items>", "@QMultiMap") - + Check("m1.0", "[0] 11", FloatValue("11"), "float") - + Check("m1.5", "[5] 22", FloatValue("22"), "float") + + Check("m1.0", "[0] 11", FloatValue("11"), "") + + Check("m1.5", "[5] 22", FloatValue("22"), "") + Check("m2", "<1 items>", "@QMultiMap<@QString, float>") + Check("m2.0.key", "\"22.0\"", "@QString") @@ -4120,23 +4120,23 @@ void tst_Dumpers::dumper_data() "map4.insert(std::pair(22, 25.0));\n") + Check("map1", "<2 items>", "std::map") - + Check("map1.0", "[0] 11", "1", "unsigned int") - + Check("map1.1", "[1] 22", "2", "unsigned int") + + Check("map1.0", "[0] 11", "1", "") + + Check("map1.1", "[1] 22", "2", "") + Check("map2", "<2 items>", "std::map") - + Check("map2.0", "[0] 11", FloatValue("11"), "float") - + Check("map2.1", "[1] 22", FloatValue("22"), "float") + + Check("map2.0", "[0] 11", FloatValue("11"), "") + + Check("map2.1", "[1] 22", FloatValue("22"), "") + Check("map3", "<6 items>", "Map") - + Check("map3.0", "[0] 11", FloatValue("11"), "float") + + Check("map3.0", "[0] 11", FloatValue("11"), "") + Check("it1.first", "11", "int") + Check("it1.second", FloatValue("11"), "float") + Check("it6.first", "66", "int") + Check("it6.second", FloatValue("66"), "float") + Check("map4", "<5 items>", "std::multimap") - + Check("map4.0", "[0] 11", FloatValue("11"), "float") - + Check("map4.4", "[4] 22", FloatValue("25"), "float"); + + Check("map4.0", "[0] 11", FloatValue("11"), "") + + Check("map4.4", "[4] 22", FloatValue("25"), ""); QTest::newRow("StdMapQt") @@ -4188,33 +4188,33 @@ void tst_Dumpers::dumper_data() + CoreProfile() + Check("map1", "<3 items>", "std::map<@QString, Foo>") - + Check("map1.0", "[0] \"22.0\"", "", "std::pair<@QString const, Foo>") + + Check("map1.0", "[0] \"22.0\"", "", "") + Check("map1.0.first", "\"22.0\"", "@QString") + Check("map1.0.second", "", "Foo") + Check("map1.0.second.a", "22", "int") - + Check("map1.1", "[1] \"33.0\"", "", "std::pair<@QString const, Foo>") + + Check("map1.1", "[1] \"33.0\"", "", "") + Check("map1.2.first", "\"44.0\"", "@QString") + Check("map1.2.second", "", "Foo") + Check("map1.2.second.a", "44", "int") + Check("map2", "<2 items>", "std::map") - + Check("map2.0", "[0] \"22.0\"", "", "std::pair") + + Check("map2.0", "[0] \"22.0\"", "", "") + Check("map2.0.first", "\"22.0\"", "char *") + Check("map2.0.first.0", "[0]", "50", "char") + Check("map2.0.second", "", "Foo") + Check("map2.0.second.a", "22", "int") - + Check("map2.1", "[1] \"33.0\"", "", "std::pair") + + Check("map2.1", "[1] \"33.0\"", "", "") + Check("map2.1.first", "\"33.0\"", "char *") + Check("map2.1.first.0", "[0]", "51", "char") + Check("map2.1.second", "", "Foo") + Check("map2.1.second.a", "33", "int") + Check("map3", "<2 items>", "std::map") - + Check("map3.0", "[0] 11", "<1 items>", "std::pair") + + Check("map3.0", "[0] 11", "<1 items>", "") + Check("map3.0.first", "11", "unsigned int") + Check("map3.0.second", "<1 items>", "@QStringList") + Check("map3.0.second.0", "[0]", "\"11\"", "@QString") - + Check("map3.1", "[1] 22", "<1 items>", "std::pair") + + Check("map3.1", "[1] 22", "<1 items>", "") + Check("map3.1.first", "22", "unsigned int") + Check("map3.1.second", "<1 items>", "@QStringList") + Check("map3.1.second.0", "[0]", "\"22\"", "@QString") @@ -4222,26 +4222,25 @@ void tst_Dumpers::dumper_data() + Check("map4.1.second.0", "[0]", "\"22\"", "@QString") + Check("map5", "<2 items>", "std::map<@QString, float>") - + Check("map5.0", "[0] \"11.0\"", FloatValue("11"), "std::pair<@QString const, float>") + + Check("map5.0", "[0] \"11.0\"", FloatValue("11"), "") + Check("map5.0.first", "\"11.0\"", "@QString") + Check("map5.0.second", FloatValue("11"), "float") - + Check("map5.1", "[1] \"22.0\"", FloatValue("22"), "std::pair<@QString const, float>") + + Check("map5.1", "[1] \"22.0\"", FloatValue("22"), "") + Check("map5.1.first", "\"22.0\"", "@QString") + Check("map5.1.second", FloatValue("22"), "float") + Check("map6", "<2 items>", "std::map") - + Check("map6.0", "[0] 11", "\"11.0\"", "std::pair") + + Check("map6.0", "[0] 11", "\"11.0\"", "") + Check("map6.0.first", "11", "int") + Check("map6.0.second", "\"11.0\"", "@QString") - + Check("map6.1", "[1] 22", "\"22.0\"", "std::pair") + + Check("map6.1", "[1] 22", "\"22.0\"", "") + Check("map6.1.first", "22", "int") + Check("map6.1.second", "\"22.0\"", "@QString") + Check("map7", "<3 items>", "std::map<@QString, @QPointer<@QObject>>") - + Check("map7.0", "[0] \".\"", "", "std::pair<@QString const, @QPointer<@QObject>>") + + Check("map7.0", "[0] \".\"", "", "") + Check("map7.0.first", "\".\"", "@QString") + Check("map7.0.second", "", "@QPointer<@QObject>") - + Check("map7.2", "[2] \"Welt\"", "", "std::pair<@QString const, @QPointer<@QObject>>") + Check("map7.2.first", "\"Welt\"", "@QString"); @@ -4672,8 +4671,8 @@ void tst_Dumpers::dumper_data() + Cxx11Profile() + Check("map1", "<2 items>", "std::unordered_map") - + Check("map1.0", "[0] 22", "2", "unsigned int") - + Check("map1.1", "[1] 11", "1", "unsigned int") + + Check("map1.0", "[0] 22", "2", "") + + Check("map1.1", "[1] 11", "1", "") + Check("map2", "<2 items>", "std::unordered_map") + Check("map2.0", "[0] \"22.0\"", FloatValue("22.0"), "") @@ -5382,17 +5381,8 @@ void tst_Dumpers::dumper_data() + Check("y2", "", "X") + Check("y3", "", "X"); - QTest::newRow("RValueReferenceLldb") + QTest::newRow("RValueReference") << Data(rvalueData) - + LldbEngine - + Check("x1", "", "X &&") - + Check("x2", "", "X &&") - + Check("x3", "", "X &&"); - - QTest::newRow("RValueReferenceGdb") - << Data(rvalueData) - + GdbEngine - + GccVersion(0, 40704) + Check("x1", "", "X &") + Check("x2", "", "X &") + Check("x3", "", "X &"); From 4f06d084fcee59911821add6cca54d94f03ab1b3 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Oct 2016 13:38:04 +0200 Subject: [PATCH 16/47] Source packages: Fix that tar.xz was not xz but gz Change-Id: I5379cdfe963f53cca04317ea51f544c40743db7b Reviewed-by: Iikka Eklund --- scripts/createSourcePackages.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/createSourcePackages.py b/scripts/createSourcePackages.py index d6e89a85fa3..af99704ac3f 100755 --- a/scripts/createSourcePackages.py +++ b/scripts/createSourcePackages.py @@ -78,7 +78,7 @@ def package_repos(repos, combined_prefix, target_file_base): print('Creating .tar.gz...') createTarGz(archive_path(crlf=False), target_file_base + '.tar.gz') print('Creating .tar.xz...') - createTarGz(archive_path(crlf=False), target_file_base + '.tar.xz') + createTarXz(archive_path(crlf=False), target_file_base + '.tar.xz') print('Creating .zip with CRLF...') createZip(archive_path(crlf=True), target_file_base + '.zip') print('Removing temporary directory...') From 779c54872a7f8d6d29fbee661636626783730060 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 26 Oct 2016 16:37:22 +0200 Subject: [PATCH 17/47] IosTool: Don't restrict the number of pending connections Apparently a failed connection counts as "pending" for a while before it is finally removed. The QML profiler aggressively tries to connect with different timeouts and multiple sockets, so quite often there is such a failed connection which then prevents new connections from getting established. We already enforce the limit of only one successful connection via the SingleRelayServer subclass. Change-Id: I441e2ed898d28f04359a9976d5b25569b8447f3f Task-number: QTCREATORBUG-17141 Reviewed-by: Christian Stenger --- src/tools/iostool/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/iostool/main.cpp b/src/tools/iostool/main.cpp index 76aa46efaba..605eff53e9d 100644 --- a/src/tools/iostool/main.cpp +++ b/src/tools/iostool/main.cpp @@ -407,7 +407,6 @@ RelayServer::~RelayServer() bool RelayServer::startServer(int port, bool ipv6) { QTC_CHECK(!m_server.isListening()); - m_server.setMaxPendingConnections(1); connect(&m_server, &QTcpServer::newConnection, this, &RelayServer::handleNewRelayConnection); quint16 portValue = static_cast(port); if (port < 0 || port > 0xFFFF) From c0ff0b72378d2d0d5aca06cb1d1a5b6fe31dac48 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 27 Oct 2016 16:04:39 +0200 Subject: [PATCH 18/47] IosTool: Always listen on both IPv4 and IPv6 We don't know which protocol QtCreator will choose to connect to the QML debug server. Currently QtCreator uses whatever "localhost" resolves to. Change-Id: Id41fb54e5eb975581d382767bdd125fbb9801f4f Task-number: QTCREATORBUG-17141 Reviewed-by: Christian Stenger --- src/tools/iostool/main.cpp | 50 ++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/tools/iostool/main.cpp b/src/tools/iostool/main.cpp index 605eff53e9d..0671cb258ce 100644 --- a/src/tools/iostool/main.cpp +++ b/src/tools/iostool/main.cpp @@ -103,7 +103,7 @@ class RelayServer: public QObject public: RelayServer(IosTool *parent); ~RelayServer(); - bool startServer(int port, bool ipv6); + bool startServer(int port); void stopServer(); quint16 serverPort(); IosTool *iosTool(); @@ -113,7 +113,8 @@ public: protected: virtual void newRelayConnection() = 0; - QTcpServer m_server; + QTcpServer m_ipv4Server; + QTcpServer m_ipv6Server; QList m_connections; }; @@ -188,7 +189,6 @@ private: int maxProgress; int opLeft; bool debug; - bool ipv6; bool inAppOutput; bool splitAppOutput; // as QXmlStreamReader reports the text attributes atomically it is better to split Ios::IosDeviceManager::AppOp appOp; @@ -404,30 +404,39 @@ RelayServer::~RelayServer() stopServer(); } -bool RelayServer::startServer(int port, bool ipv6) +bool RelayServer::startServer(int port) { - QTC_CHECK(!m_server.isListening()); - connect(&m_server, &QTcpServer::newConnection, this, &RelayServer::handleNewRelayConnection); + QTC_CHECK(!m_ipv4Server.isListening()); + QTC_CHECK(!m_ipv6Server.isListening()); + connect(&m_ipv4Server, &QTcpServer::newConnection, + this, &RelayServer::handleNewRelayConnection); + connect(&m_ipv6Server, &QTcpServer::newConnection, + this, &RelayServer::handleNewRelayConnection); quint16 portValue = static_cast(port); if (port < 0 || port > 0xFFFF) return false; - if (ipv6) - return m_server.listen(QHostAddress(QHostAddress::LocalHostIPv6), portValue); - else - return m_server.listen(QHostAddress(QHostAddress::LocalHost), portValue); + m_ipv4Server.listen(QHostAddress(QHostAddress::LocalHostIPv6), portValue); + m_ipv6Server.listen(QHostAddress(QHostAddress::LocalHost), portValue); + return m_ipv4Server.isListening() || m_ipv6Server.isListening(); } void RelayServer::stopServer() { foreach (Relayer *connection, m_connections) delete connection; - if (m_server.isListening()) - m_server.close(); + if (m_ipv4Server.isListening()) + m_ipv4Server.close(); + if (m_ipv6Server.isListening()) + m_ipv6Server.close(); } quint16 RelayServer::serverPort() { - return m_server.serverPort(); + if (m_ipv4Server.isListening()) + return m_ipv4Server.serverPort(); + if (m_ipv6Server.isListening()) + return m_ipv6Server.serverPort(); + return 0; } IosTool *RelayServer::iosTool() @@ -458,11 +467,12 @@ SingleRelayServer::SingleRelayServer(IosTool *parent, void SingleRelayServer::newRelayConnection() { + QTcpSocket *clientSocket = m_ipv4Server.hasPendingConnections() + ? m_ipv4Server.nextPendingConnection() : m_ipv6Server.nextPendingConnection(); if (m_connections.size() > 0) { - delete m_server.nextPendingConnection(); + delete clientSocket; return; } - QTcpSocket *clientSocket = m_server.nextPendingConnection(); if (clientSocket) { Relayer *newConnection = new Relayer(this, clientSocket); m_connections.append(newConnection); @@ -482,7 +492,8 @@ GenericRelayServer::GenericRelayServer(IosTool *parent, int remotePort, void GenericRelayServer::newRelayConnection() { - QTcpSocket *clientSocket = m_server.nextPendingConnection(); + QTcpSocket *clientSocket = m_ipv4Server.hasPendingConnections() + ? m_ipv4Server.nextPendingConnection() : m_ipv6Server.nextPendingConnection(); if (clientSocket) { iosTool()->errorMsg(QString::fromLatin1("setting up relayer for new connection")); RemotePortRelayer *newConnection = new RemotePortRelayer(this, clientSocket); @@ -497,7 +508,6 @@ IosTool::IosTool(QObject *parent): maxProgress(0), opLeft(0), debug(false), - ipv6(false), inAppOutput(false), splitAppOutput(true), appOp(Ios::IosDeviceManager::None), @@ -547,8 +557,6 @@ void IosTool::run(const QStringList &args) appOp = Ios::IosDeviceManager::AppOp(appOp | Ios::IosDeviceManager::Run); } else if (arg == QLatin1String("--noninteractive")) { // ignored for compatibility - } else if (arg == QLatin1String("--ipv6")) { - ipv6 = true; } else if (arg == QLatin1String("-v") || arg == QLatin1String("--verbose")) { echoRelays = true; } else if (arg == QLatin1String("-d") || arg == QLatin1String("--debug")) { @@ -720,12 +728,12 @@ void IosTool::didStartApp(const QString &bundlePath, const QString &deviceId, int qmlPort = deviceSession->qmljsDebugPort(); if (qmlPort) { qmlServer = new GenericRelayServer(this, qmlPort, deviceSession); - qmlServer->startServer(0, ipv6); + qmlServer->startServer(0); } } if (debug) { gdbServer = new SingleRelayServer(this, gdbFd); - if (!gdbServer->startServer(0, ipv6)) { + if (!gdbServer->startServer(0)) { doExit(-4); return; } From ff2168948778da058467cb3698ec8023cbc4a73a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Oct 2016 16:22:03 +0200 Subject: [PATCH 19/47] iOS: Make runSimCtlCommand static Doesn't depend on state. Change-Id: I6c0004bf6b6d1e30171b08e1b404d82242c42d99 Reviewed-by: Tobias Hunger Reviewed-by: Vikas Pachdha --- src/plugins/ios/simulatorcontrol.cpp | 29 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp index a2807996a46..b300e77e6d5 100644 --- a/src/plugins/ios/simulatorcontrol.cpp +++ b/src/plugins/ios/simulatorcontrol.cpp @@ -64,6 +64,16 @@ static bool checkForTimeout(const std::chrono::time_point< std::chrono::high_res return timedOut; } +static QByteArray runSimCtlCommand(QStringList args) +{ + QProcess simCtlProcess; + args.prepend(QStringLiteral("simctl")); + simCtlProcess.start(QStringLiteral("xcrun"), args, QProcess::ReadOnly); + if (!simCtlProcess.waitForFinished()) + qCDebug(simulatorLog) << "simctl command failed." << simCtlProcess.errorString(); + return simCtlProcess.readAll(); +} + class SimulatorControlPrivate :QObject { Q_OBJECT private: @@ -79,7 +89,6 @@ private: SimulatorControlPrivate(QObject *parent = nullptr); ~SimulatorControlPrivate(); - QByteArray runSimCtlCommand(QStringList args) const; SimDeviceInfo deviceInfo(const QString &simUdid) const; bool runCommand(QString command, const QStringList &args, QByteArray *output = nullptr); @@ -105,7 +114,7 @@ QList SimulatorControl::availableSimulators() void SimulatorControl::updateAvailableSimulators() { - const QByteArray output = d->runSimCtlCommand({QLatin1String("list"), QLatin1String("-j"), QLatin1String("devices")}); + const QByteArray output = runSimCtlCommand({QLatin1String("list"), QLatin1String("-j"), QLatin1String("devices")}); QJsonDocument doc = QJsonDocument::fromJson(output); if (!doc.isNull()) { QList availableDevices; @@ -185,7 +194,7 @@ bool SimulatorControl::installApp(const QString &simUdid, const Utils::FileName { bool installed = false; if (isSimulatorRunning(simUdid)) { - commandOutput = d->runSimCtlCommand(QStringList() << QStringLiteral("install") << simUdid << bundlePath.toString()); + commandOutput = runSimCtlCommand(QStringList() << QStringLiteral("install") << simUdid << bundlePath.toString()); installed = commandOutput.isEmpty(); } else { commandOutput = "Simulator device not running."; @@ -199,7 +208,7 @@ qint64 SimulatorControl::launchApp(const QString &simUdid, const QString &bundle pId = -1; if (!bundleIdentifier.isEmpty() && isSimulatorRunning(simUdid)) { const QStringList args({QStringLiteral("launch"), simUdid , bundleIdentifier}); - const QByteArray output = d->runSimCtlCommand(args); + const QByteArray output = runSimCtlCommand(args); const QByteArray pIdStr = output.trimmed().split(' ').last().trimmed(); bool validInt = false; pId = pIdStr.toLongLong(&validInt); @@ -264,16 +273,6 @@ SimulatorControlPrivate::~SimulatorControlPrivate() } -QByteArray SimulatorControlPrivate::runSimCtlCommand(QStringList args) const -{ - QProcess simCtlProcess; - args.prepend(QStringLiteral("simctl")); - simCtlProcess.start(QStringLiteral("xcrun"), args, QProcess::ReadOnly); - if (!simCtlProcess.waitForFinished()) - qCDebug(simulatorLog) << "simctl command failed." << simCtlProcess.errorString(); - return simCtlProcess.readAll(); -} - // The simctl spawns the process and returns the pId but the application process might not have started, at least in a state where you can interrupt it. // Use SimulatorControl::waitForProcessSpawn to be sure. QProcess *SimulatorControl::spawnAppProcess(const QString &simUdid, const Utils::FileName &bundlePath, qint64 &pId, bool waitForDebugger, const QStringList &extraArgs) @@ -282,7 +281,7 @@ QProcess *SimulatorControl::spawnAppProcess(const QString &simUdid, const Utils: if (isSimulatorRunning(simUdid)) { QString bundleId = bundleIdentifier(bundlePath); QString executableName = bundleExecutable(bundlePath); - QByteArray appPath = d->runSimCtlCommand(QStringList() << QStringLiteral("get_app_container") << simUdid << bundleId).trimmed(); + QByteArray appPath = runSimCtlCommand(QStringList() << QStringLiteral("get_app_container") << simUdid << bundleId).trimmed(); if (!appPath.isEmpty() && !executableName.isEmpty()) { // Spawn the app. The spawned app is started in suspended mode. appPath.append('/' + executableName.toLocal8Bit()); From 424005c91183edb72000ed795522c1256d68de13 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 28 Oct 2016 12:53:24 +0200 Subject: [PATCH 20/47] QmlJS: Release the same documents we keep before When rescanning imports we generally get a new version of the parent document. When replacing the cached documents we want to release the old ones, not the new ones. Failing to do so leads to types disappearing from the QML code model and to leaking memory. Task-number: QTCREATORBUG-17175 Change-Id: I3994444ac0a6cd87f9d9d0b47ab3d6015660e416 Reviewed-by: Thomas Hartmann --- src/libs/qmljs/qmljsmodelmanagerinterface.cpp | 33 ++++++++++--------- src/libs/qmljs/qmljsmodelmanagerinterface.h | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index e0983433916..34d1cd24959 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -1300,7 +1300,7 @@ void ModelManagerInterface::updateCppQmlTypes(QFutureInterface &interface, interface.setProgressValue(0); CppDataHash newData; - QHash newDeclarations; + QHash > newDeclarations; { QMutexLocker locker(&qmlModelManager->m_cppDataMutex); newData = qmlModelManager->m_cppDataHash; @@ -1321,33 +1321,36 @@ void ModelManagerInterface::updateCppQmlTypes(QFutureInterface &interface, const QString fileName = doc->fileName(); if (!scan) { hasNewInfo = newData.remove(fileName) > 0 || hasNewInfo; - foreach (const QString &file, newDeclarations[fileName]) { - CPlusPlus::Document::Ptr doc = snapshot.document(file); - if (doc.isNull()) - continue; - finder(doc); - hasNewInfo = rescanExports(file, finder, newData) || hasNewInfo; + foreach (const CPlusPlus::Document::Ptr &savedDoc, newDeclarations.value(fileName)) { + finder(savedDoc); + hasNewInfo = rescanExports(savedDoc->fileName(), finder, newData) || hasNewInfo; } continue; } for (auto it = newDeclarations.begin(), end = newDeclarations.end(); it != end;) { - if (it->removeOne(fileName)) { - doc->releaseSourceAndAST(); - if (it->isEmpty()) { - it = newDeclarations.erase(it); - continue; + for (auto docIt = it->begin(), endDocIt = it->end(); docIt != endDocIt;) { + CPlusPlus::Document::Ptr &savedDoc = *docIt; + if (savedDoc->fileName() == fileName) { + savedDoc->releaseSourceAndAST(); + it->erase(docIt); + break; + } else { + ++docIt; } } - ++it; + if (it->isEmpty()) + it = newDeclarations.erase(it); + else + ++it; } foreach (const QString &declarationFile, finder(doc)) { - newDeclarations[declarationFile].append(fileName); + newDeclarations[declarationFile].append(doc); doc->keepSourceAndAST(); // keep for later reparsing when dependent doc changes } - hasNewInfo = rescanExports(doc->fileName(), finder, newData) || hasNewInfo; + hasNewInfo = rescanExports(fileName, finder, newData) || hasNewInfo; doc->releaseSourceAndAST(); } diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index 3f640c6ca78..2cb02083f6e 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -275,7 +275,7 @@ private: QrcCache m_qrcCache; CppDataHash m_cppDataHash; - QHash m_cppDeclarationFiles; + QHash > m_cppDeclarationFiles; mutable QMutex m_cppDataMutex; // project integration From 1562ec7bceb438ea8b293b3a2ccf01c730b31a57 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 28 Oct 2016 16:03:17 +0200 Subject: [PATCH 21/47] Doc: Using code completion in Binding Editor in Design mode Change-Id: I4889d6d247f6d8d8cb758c65eea917736f33262d Reviewed-by: Thomas Hartmann --- doc/images/qmldesigner-binding-editor.png | Bin 0 -> 4100 bytes doc/images/qmldesigner-set-expression.png | Bin 11412 -> 4844 bytes doc/src/qtquick/qtquick-screens.qdoc | 13 ++++++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 doc/images/qmldesigner-binding-editor.png diff --git a/doc/images/qmldesigner-binding-editor.png b/doc/images/qmldesigner-binding-editor.png new file mode 100644 index 0000000000000000000000000000000000000000..7c8edfd90d143dc1a8521ba974a0614c76f8345f GIT binary patch literal 4100 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 literal 0 HcmV?d00001 diff --git a/doc/images/qmldesigner-set-expression.png b/doc/images/qmldesigner-set-expression.png index 4d1ad5152bcd31f8855554cb255364af195a5508..bbcbd0944258d18534fb6964668324fa7eb067ee 100644 GIT binary patch literal 4844 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 literal 11412 zcmeAS@N?(olHy`uVBq!ia0y~yVEDkmz);1(#K6G7C*xVoz@QWD>EaktaqI2e@6n;| zzYct6f8+oA@H_tBZ}P5*`08kAFm)-o3T_aekhb{N1U|3e&aQQ)g1aS-%{Kz_wy!Ce*FBoyKvQX2j?dp zg33)zO;z9CynOrCw~2|F`FM}yVTLa!C##>IZ~uHhOZB%mlJj=R+t>9l&+iu3|M%l@ z|DP>I3uI+wgM)(d?(g%x7P5C+-rZXV4>o$AJ9q9+PO8Ap7H6AKiIplp4xFvO=+-i^ z>&=~=n|FPm`{IFK>@FGmx<8+up1!icY37n!H*W?`O>o{iNpRC*qZ6@0Z1r_s8y{rk z3fPEFPq}lv{xD?CSSJSuj}sYeE8h@+J*a)DgXZbv`M?UDRsyC`2BtV z@9nLgt`iv)6VoFtWtMZJ;NPFhO9gLkY`nbO|NX74rw<=i*46D@v_{c3Hr64SQQ5uk z&*Of3CnqPD-ibva;bCE6Sy@`TlJgav+jwLwF5JC4x2mh7gP}GspJC#>dG}TZt7~ma zKHhh@o&WpSuV24>kul4WNbLA4eXL$V_twSk zUa~}`$h`br%&MLxd{QPIZ+7h5Iq}?w4<8yD8uIS$5^Uf(q$K%VNb>#l_445-jd-Uf zDQ?)mzuwL5*p9--zrMV5KC`#_`!g{S76&h537d)!D*_j5oVj2B|E^YpTGXketE)mo zK0iA<+f`UUcGs5d>+4cx{JOm@_x9c0<;ls(nJ;#izh5S{u=4J%Qj_4WgwxY>O{Z+g zVzDwd7XGW~5UkB$m3?guE4P@8ZPgSp@0*uOPA2!u+3qO$^u*JMd+`_h+uQT)69v4Q zXVrau6`GQwlK8;F++5sC&aS3|OTxZx&!zhOo0l5yE?Ttc;$rvr_xI0#^MG>}x453m z=>^StF*_XgEtoJ#W$uzWXC}!S&6qHu;dz&+_Jy#(z(AL+$;bQT>wYl0e!J{%@5p5H z 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 Date: Fri, 28 Oct 2016 15:16:41 +0200 Subject: [PATCH 22/47] Update qbs submodule To HEAD of 1.6 branch. Change-Id: Ideda150d8126e09fa105b3b85848f7af102a29d4 Reviewed-by: Joerg Bornemann --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 704eb30d271..738ed8e5c0d 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 704eb30d27117d88e3edbe5d255ea5b8989509f3 +Subproject commit 738ed8e5c0de334d780659bbef8a360154a87221 From 2cab55ea1ae664e0677c6508efad4a52c181c1f5 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 28 Oct 2016 16:10:18 +0200 Subject: [PATCH 23/47] QmlDesigner: Allow JavaScrip blocks in Connections in .ui.qml Inside a Connections item JavaScript blocks should be allowed. Change-Id: Ia6a08fc575a72980bd53a32249bf302b7a426266 Reviewed-by: Marco Benelli --- src/libs/qmljs/qmljscheck.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libs/qmljs/qmljscheck.cpp b/src/libs/qmljs/qmljscheck.cpp index c9c136d1781..936beec915f 100644 --- a/src/libs/qmljs/qmljscheck.cpp +++ b/src/libs/qmljs/qmljscheck.cpp @@ -1252,7 +1252,12 @@ bool Check::visit(BinaryExpression *ast) bool Check::visit(Block *ast) { - addMessage(ErrBlocksNotSupportedInQmlUi, locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation())); + + bool isDirectInConnectionsScope = + (!m_typeStack.isEmpty() && m_typeStack.last() == QLatin1String("Connections")); + + if (!isDirectInConnectionsScope) + addMessage(ErrBlocksNotSupportedInQmlUi, locationFromRange(ast->firstSourceLocation(), ast->lastSourceLocation())); if (Node *p = parent()) { if (!cast(p) From 501bf4918fb36798bd8b490c38ba8f6febb7c882 Mon Sep 17 00:00:00 2001 From: Rafael Roquetto Date: Fri, 28 Oct 2016 14:38:20 -0200 Subject: [PATCH 24/47] Fix CDB detection To make sure CDB is really installed on a Windows Kit, we need to assure the 'inc' subdirectory is present. Before this patch, if, for instance, the Windows 8.1 kit is present (including a Debuggers subdirectory), but without CDB, the first test under "32-bit" qmake will yield a false positive, preventing the following 32-bit kits to be tested, then to fail under the 64-bit qmake test because the 'inc' directory is inexistent, finally bringing about an empty CDB_PATH variable. Change-Id: I1d7cf3350f4a63a556ef106faa5b3f0593dcf8c8 Reviewed-by: Andrew Knight Reviewed-by: Brett Stottlemyer Reviewed-by: David Schulz --- src/libs/qtcreatorcdbext/cdb_detect.pri | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/qtcreatorcdbext/cdb_detect.pri b/src/libs/qtcreatorcdbext/cdb_detect.pri index 286d9f20c30..ae09e258d4d 100644 --- a/src/libs/qtcreatorcdbext/cdb_detect.pri +++ b/src/libs/qtcreatorcdbext/cdb_detect.pri @@ -14,9 +14,9 @@ msvc { # Starting from Windows SDK 8, the headers and libs are under 'ProgramFiles (x86)'. # The libraries are under 'ProgramFiles'as well, so, check for existence of 'inc'. # 32bit qmake: - !exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Windows Kits/8.0/Debuggers" - !exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Windows Kits/8.1/Debuggers" - !exists($$CDB_PATH):CDB_PATH="$$(ProgramFiles)/Windows Kits/10/Debuggers" + !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/8.0/Debuggers" + !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/8.1/Debuggers" + !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles)/Windows Kits/10/Debuggers" # 64bit qmake: !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles) (x86)/Windows Kits/8.0/Debuggers" !exists($$CDB_PATH/inc):CDB_PATH="$$(ProgramFiles) (x86)/Windows Kits/8.1/Debuggers" From 75c5afef486c604e45335c9888557fcdac914bf6 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Fri, 28 Oct 2016 17:05:56 +0200 Subject: [PATCH 25/47] Doc: Setting when property for state in Design mode Change-Id: I3462f7c5a8ea436d979c12bc02ae1e2f063eeb4b Reviewed-by: Thomas Hartmann --- doc/images/qmldesigner-transitions.png | Bin 2713 -> 3229 bytes doc/src/qtquick/qtquick-designer.qdoc | 4 ++++ 2 files changed, 4 insertions(+) diff --git a/doc/images/qmldesigner-transitions.png b/doc/images/qmldesigner-transitions.png index 66624e93d269d9ba8121ab79e678be54463af73f..f3599b7ca66f19f53c0ca774a69e5c446893c5e8 100644 GIT binary patch literal 3229 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 Co{?7o literal 2713 zcmeAS@N?(olHy`uVBq!ia0y~yVANq?V5s0=W?*2bKW#6>z`*o9z$e7j-{0TC$>sn5 z|7Xu%(W<|apPz4PYU=Fjrmm?aDk^GdXlQI=Vqjn(EG+Ej=jY+!X=P<)VPT=7qQWg_ zq?oeY)y>V`-aaxi(%08lv*x^{UlWh2-RIArRSWkWK6*;kw?xG{XyM}J!d8j)j?Vf< zCaS8c+S=NILBVbwUMcCB$;l~d8k%?R+-_)WjE;@-^zwCdcHOjRVQ@%rXn0geScJQi z%eiys>KhmP$CcaKJ8D*+U9f18Lty@i)8|v_=FOi!XTrpZKCRzQHrDZR^5D7w@S3 z$1WT=awM{7dVfQGQE{=eXKGP)jGb$sk6(bFlgq7JH&^XHf8xTaJx5mV-Lr7U-1(~( z%_}aOuw!*^S6BDEp3K;Uq=wx1#w1^Nce_x3(|wn(U%PQNb@s*0$4;~^IZ!rz`{8q| z(%V;^KDnZC!iv=^miEn_UsyG_rfd5A`Mu3;o%NZuu2Cgb4aLo+#qmkSfuXtm#R;*2 z(f$D;1+jkirlwi(#?y{poxI`L^20~g?l`dR^v3H~Hf%nyp=ZI`qK>6&XH7b=eL_fD zZ%S!LY;NFxcO&g_|TaL?`oyU!ikdG_#zlN&e8KeBe)zC|bZE@EJqId$^%wA@LjS5I(u?w>lb zWpQ6qVsib2p344~y!QOO{HWZ5g0!NjYx>&yQ`2LH>4qe^bvt>`>(&bw=EnPl!iT#Advos+{Y+l=t& zhMdycmabB3heC(oY!j2L33-0&r>gH;p!Vg>i|+lWRg3mH%v@hwyxwu|$VGkM(qM45_&F_D*@g&QBA&EM(Y z(Uj1jev3&jr>@x~8FsvR{@D#G-}e8K^?bWjZH-vz%|$UsRpS062dY$`vCvud_~2|= zO{1k+eVgX5UGj(}(v~5P) z)VD|N?>;v1w4Sx$&?B?_8yg;0Etr^cId6?~)^?NhxW5eFZd_03Sn2yuDK~hQ$?9F{ zIrFy~3T7Ukv_ndDiqB2|If)UQ`68nfb$_2)xi!lmUTsaOzx?{h&ClwXRZm`9eY)p? z++xYO3GSv=Vba3lI~M<3pT9IDqW4#uPoc8ms-QN{Nj*<5@nmY=_KLa0>K)YFX?A## z5WlKXf9lGsaar4bpPVUkQP}rb(TBCwyWc%LJhxpnIrKa4{Wrpv6+6-*>($f$ADh)+ zSa`FXN9vvE&e}5`hc6vF?Ut3N;JEzO)j4yrS9#uA|9OtF8Z1$D&>sIYO#dLb#-Z?wh`b2!5 zzGg>p&A&tP5wrc)X6(*7zvM#R<8aIN_iwKrv-c7gmfg4AUHX4V*5a~XXI_|w&TSIi zqrwzxGDpI4!`98qt#|)d0CPjrllMDJ8cQ; zv{jo}ukCG3m)EhWeaIemR&DWp3)lIb(zlnHK3cIZJ9f5Y$oEgNy$x*NUpA}@-p~|Q z=OR9@PMB@s;#o(|%`Wh~$$L>|&66yj{dWVVRh|9xt|VjH(YzI_8rRg7r_bGO@aW6R zyysE>4g_7kI_J=>6#2Y1)50?*^BL5Ir^TNy_ukek{kBK%+m{(qVwtRBo=bH;m_*&) zo4W28&u!j`VUO0j80&0IX3Fhs-E`nm&x>V_SA%AKvoO8IzWU2GRu(_$8zF0X=d^`= zf8e=Gmy>yxxzvKHx65*+N|x>n+g^6s;hEBk{_`(h`Zg~!m1?M);S#w~S}Ij<%Jx$; z0(UERX-&CtlBYY*EqdKIEwxClY4y|fVxtTsPi|>lrji-E?Cyk;g*TFqB`$1t?muQJ zy;8HuC)tEwU!k$q-+N}?nY6iao=ZNgWUg^(7L=PN@n}ZJ24#i5n@Vf`ShmK?IWZVU zRC0fgZB(-Pu3@j(5V59)<-F*LW5ulh^VeLu7OE1Q7gxMDR)5&w#4D@y{c3K>>^0ptEhEzGzS`Vh|A6)DBg;0fW{(g1 zvd&ZdUrFYSFJ`~ZrbklIQ#pt72Gz5 zW=Y(%-sAWEqpVrE_3g=X^O;5WR)3SQf9H~Vdr%HDmJQ{-O8_jUH;4YQ4>So$9M| z?cy}KH}h_M(n$DQDJ55U{@A=0bKalFPNn)X)$cxR9;W&FRLp#<1J5HHSR)!*nRI#> zxRnna;@Duoq;qf6$^*8yc)G9efABngW7o%sizNrOzL?5i*XlU4@srr|^>cK>=1tlo z8f8|y;Zw@9oFuA|@nqz6Q|Iwh85boX6m35>%-b6$&iX|*%iI89vb8Bc7Oh`m$*8NGo`8hmJOnW_V{!LDv z({6|2&2+Ba75Wnz8WE8*^G*FlhH0)?b%M=%c+@^jZr|^)DbMe5v7OeN{z2P?L*e%O ZjEZ(G+2W;l85kHCJYD@<);T3K0RS-SC;0#X diff --git a/doc/src/qtquick/qtquick-designer.qdoc b/doc/src/qtquick/qtquick-designer.qdoc index 7a143d24c4a..81d7ebcfa24 100644 --- a/doc/src/qtquick/qtquick-designer.qdoc +++ b/doc/src/qtquick/qtquick-designer.qdoc @@ -428,6 +428,10 @@ you can change the position of an object on the canvas and then add animation to the change between the states. + To determine when the state should be applied, select + \uicontrol {Set when Condition} in the context menu and specify a + \l [QtQuick]{State::when}{when} property for the state. + You can preview the states in the \uicontrol State pane and click them to switch between states on the canvas. From 1d6d799d22ad1463428c7d119c15763d795125c4 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 30 Oct 2016 12:01:38 +0200 Subject: [PATCH 26/47] ToolChain: Compare also by language Otherwise C/C++ with the same ABI are detected as duplicates. Change-Id: I99090b4cc776047b1ecb958242d0b4f5ecec5f0a Reviewed-by: Tobias Hunger --- src/plugins/projectexplorer/toolchain.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index 3dbe7d90412..a09586b5e00 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -202,7 +202,9 @@ bool ToolChain::operator == (const ToolChain &tc) const return true; // We ignore displayname - return typeId() == tc.typeId() && isAutoDetected() == tc.isAutoDetected(); + return typeId() == tc.typeId() + && isAutoDetected() == tc.isAutoDetected() + && language() == tc.language(); } /*! From a9c967263ebc586dc7131abe030830763a7f3aeb Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 30 Oct 2016 12:03:04 +0200 Subject: [PATCH 27/47] MSVC: Minor cleanup Change-Id: I4aa9684e04e57a96c3fc624236c2c95817306d76 Reviewed-by: Tobias Hunger --- src/plugins/projectexplorer/msvctoolchain.cpp | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index c7e5de51962..859c9f78681 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -743,19 +743,18 @@ QList MsvcToolChainFactory::autoDetect(const QList &al continue; QList tmp; - tmp.append(findOrCreateToolChain(alreadyKnown, - generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::x86), - findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::x86, sdkKey), - fi.absoluteFilePath(), QLatin1String("/x86"), ToolChain::AutoDetection)); - // Add all platforms, cross-compiler is automatically selected by SetEnv.cmd if needed - tmp.append(findOrCreateToolChain(alreadyKnown, - generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::amd64), - findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::amd64, sdkKey), - fi.absoluteFilePath(), QLatin1String("/x64"), ToolChain::AutoDetection)); - tmp.append(findOrCreateToolChain(alreadyKnown, - generateDisplayName(name, MsvcToolChain::WindowsSDK, MsvcToolChain::ia64), - findAbiOfMsvc(MsvcToolChain::WindowsSDK, MsvcToolChain::ia64, sdkKey), - fi.absoluteFilePath(), QLatin1String("/ia64"), ToolChain::AutoDetection)); + const QVector > platforms = { + {MsvcToolChain::x86, "x86"}, + {MsvcToolChain::amd64, "x64"}, + {MsvcToolChain::ia64, "ia64"}, + }; + for (auto platform: platforms) { + tmp.append(findOrCreateToolChain( + alreadyKnown, + generateDisplayName(name, MsvcToolChain::WindowsSDK, platform.first), + findAbiOfMsvc(MsvcToolChain::WindowsSDK, platform.first, sdkKey), + fi.absoluteFilePath(), "/" + platform.second, ToolChain::AutoDetection)); + } // Make sure the default is front. if (folder == defaultSdkPath) results = tmp + results; @@ -786,14 +785,16 @@ QList MsvcToolChainFactory::autoDetect(const QList &al const int version = vsName.leftRef(dotPos).toInt(); const QString vcvarsAllbat = path + QLatin1String("/vcvarsall.bat"); if (QFileInfo(vcvarsAllbat).isFile()) { - QList platforms; // prioritized list + // prioritized list. // x86_arm was put before amd64_arm as a workaround for auto detected windows phone // toolchains. As soon as windows phone builds support x64 cross builds, this change // can be reverted. - platforms << MsvcToolChain::x86 << MsvcToolChain::amd64_x86 - << MsvcToolChain::amd64 << MsvcToolChain::x86_amd64 - << MsvcToolChain::arm << MsvcToolChain::x86_arm << MsvcToolChain::amd64_arm - << MsvcToolChain::ia64 << MsvcToolChain::x86_ia64; + const QVector platforms = { + MsvcToolChain::x86, MsvcToolChain::amd64_x86, + MsvcToolChain::amd64, MsvcToolChain::x86_amd64, + MsvcToolChain::arm, MsvcToolChain::x86_arm, MsvcToolChain::amd64_arm, + MsvcToolChain::ia64, MsvcToolChain::x86_ia64 + }; foreach (const MsvcToolChain::Platform &platform, platforms) { const bool toolchainInstalled = QFileInfo(vcVarsBatFor(path, platform)).isFile(); if (hostSupportsPlatform(platform) && toolchainInstalled) { From 36ecee17fe59da7787d134036629e142515e5321 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Sun, 30 Oct 2016 12:03:21 +0200 Subject: [PATCH 28/47] MSVC: Register toolchains also for C language Change-Id: I1abaecc53be9e87b88178bc044e3352ddeb5c4e6 Reviewed-by: Tobias Hunger --- src/plugins/projectexplorer/msvctoolchain.cpp | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 859c9f78681..fab0226c40b 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -573,7 +573,7 @@ MsvcToolChainFactory::MsvcToolChainFactory() QSet MsvcToolChainFactory::supportedLanguages() const { - return { ProjectExplorer::ToolChain::Language::Cxx }; + return { ToolChain::Language::C, ToolChain::Language::Cxx }; } bool MsvcToolChainFactory::checkForVisualStudioInstallation(const QString &vsName) @@ -617,24 +617,32 @@ QString MsvcToolChainFactory::vcVarsBatFor(const QString &basePath, MsvcToolChai return QString(); } -static ToolChain *findOrCreateToolChain(const QList &alreadyKnown, - const QString &name, const Abi &abi, - const QString &varsBat, const QString &varsBatArg, - ToolChain::Detection d = ToolChain::ManualDetection) +static QList findOrCreateToolChain( + const QList &alreadyKnown, + const QString &name, const Abi &abi, + const QString &varsBat, const QString &varsBatArg, + ToolChain::Detection d = ToolChain::ManualDetection) { - ToolChain *tc = Utils::findOrDefault(alreadyKnown, - [&varsBat, &varsBatArg, &abi](ToolChain *tc) -> bool { - if (tc->typeId() != Constants::MSVC_TOOLCHAIN_TYPEID) - return false; - if (tc->targetAbi() != abi) - return false; - auto mtc = static_cast(tc); - return mtc->varsBat() == varsBat - && mtc->varsBatArg() == varsBatArg; - }); - if (!tc) - tc = new MsvcToolChain(name, abi, varsBat, varsBatArg, ToolChain::Language::Cxx, d); - return tc; + QList res; + for (auto language: {ToolChain::Language::C, ToolChain::Language::Cxx}) { + ToolChain *tc = Utils::findOrDefault( + alreadyKnown, + [&varsBat, &varsBatArg, &abi, &language](ToolChain *tc) -> bool { + if (tc->typeId() != Constants::MSVC_TOOLCHAIN_TYPEID) + return false; + if (tc->targetAbi() != abi) + return false; + if (tc->language() != language) + return false; + auto mtc = static_cast(tc); + return mtc->varsBat() == varsBat + && mtc->varsBatArg() == varsBatArg; + }); + if (!tc) + tc = new MsvcToolChain(name, abi, varsBat, varsBatArg, language, d); + res << tc; + } + return res; } // Detect build tools introduced with MSVC2015 @@ -670,10 +678,11 @@ static void detectCppBuildTools(QList *list) const Entry &e = entries[i]; const Abi abi(e.architecture, Abi::WindowsOS, Abi::WindowsMsvc2015Flavor, e.format, e.wordSize); - list->append(new MsvcToolChain(name + QLatin1String(e.postFix), abi, - vcVarsBat, QLatin1String(e.varsBatArg), - ToolChain::Language::Cxx, - ToolChain::AutoDetection)); + for (auto language: {ToolChain::Language::C, ToolChain::Language::Cxx}) { + list->append(new MsvcToolChain(name + QLatin1String(e.postFix), abi, + vcVarsBat, QLatin1String(e.varsBatArg), + language, ToolChain::AutoDetection)); + } } } From f87362990a9fcd45e2c0185890a7529665f94dbe Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 28 Oct 2016 16:33:27 +0200 Subject: [PATCH 29/47] Update qbs submodule To HEAD of master branch. Change-Id: I8aff6a4685fc5f900037e5703b6c2f00b1996ff4 Reviewed-by: Jake Petroules --- src/shared/qbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/qbs b/src/shared/qbs index 830503d0470..7a8a21c03b8 160000 --- a/src/shared/qbs +++ b/src/shared/qbs @@ -1 +1 @@ -Subproject commit 830503d04708ebd6a64dfd260b35cfeea26ba60a +Subproject commit 7a8a21c03b8e49e7dbf0462d2c698e960bdacbb4 From f1d3e7c8e7712a5c4edb23e03b14294035389ed5 Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Thu, 27 Oct 2016 16:44:45 +0200 Subject: [PATCH 30/47] runextensions: Add convenience method for result handler Change-Id: Ibe7e62049f165276fdedcd04d8311324f6bc5d19 Reviewed-by: Tobias Hunger --- src/libs/utils/runextensions.h | 55 +++++++++++++++++ .../auto/runextensions/tst_runextensions.cpp | 59 +++++++++++++++++++ 2 files changed, 114 insertions(+) diff --git a/src/libs/utils/runextensions.h b/src/libs/utils/runextensions.h index 43a25411d6e..0ba0b8c3c53 100644 --- a/src/libs/utils/runextensions.h +++ b/src/libs/utils/runextensions.h @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -493,4 +494,58 @@ runAsync(QThreadPool *pool, Function &&function, Args&&... args) std::forward(args)...); } + +/*! + Adds a handler for when a result is ready. + This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions + or create a QFutureWatcher already for other reasons. +*/ +template +const QFuture &onResultReady(const QFuture &future, R *receiver, void(R::*member)(const T &)) +{ + auto watcher = new QFutureWatcher(); + watcher->setFuture(future); + QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); + QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, receiver, + [receiver, member, watcher](int index) { + (receiver->*member)(watcher->future().resultAt(index)); + }); + return future; +} + +/*! + Adds a handler for when a result is ready. The guard object determines the lifetime of + the connection. + This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions + or create a QFutureWatcher already for other reasons. +*/ +template +const QFuture &onResultReady(const QFuture &future, QObject *guard, Function f) +{ + auto watcher = new QFutureWatcher(); + watcher->setFuture(future); + QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); + QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, guard, [f, watcher](int index) { + f(watcher->future().resultAt(index)); + }); + return future; +} + +/*! + Adds a handler for when a result is ready. + This creates a new QFutureWatcher. Do not use if you intend to react on multiple conditions + or create a QFutureWatcher already for other reasons. +*/ +template +const QFuture &onResultReady(const QFuture &future, Function f) +{ + auto watcher = new QFutureWatcher(); + watcher->setFuture(future); + QObject::connect(watcher, &QFutureWatcherBase::finished, watcher, &QObject::deleteLater); + QObject::connect(watcher, &QFutureWatcherBase::resultReadyAt, [f, watcher](int index) { + f(watcher->future().resultAt(index)); + }); + return future; +} + } // Utils diff --git a/tests/auto/runextensions/tst_runextensions.cpp b/tests/auto/runextensions/tst_runextensions.cpp index f1d77fa0605..acad21b15d2 100644 --- a/tests/auto/runextensions/tst_runextensions.cpp +++ b/tests/auto/runextensions/tst_runextensions.cpp @@ -44,6 +44,7 @@ private slots: void threadPriority(); void runAsyncNoFutureInterface(); void crefFunction(); + void onResultReady(); }; void report3(QFutureInterface &fi) @@ -557,6 +558,64 @@ void tst_RunExtensions::crefFunction() QCOMPARE(value, true); } +class ObjWithProperty : public QObject +{ + Q_OBJECT + +public slots: + void setValue(const QString &s) + { + value = s; + } + +public: + QString value; +}; + +void tst_RunExtensions::onResultReady() +{ + { // lambda + QFuture f = Utils::runAsync([](QFutureInterface &fi) { + fi.reportResult("Hi"); + fi.reportResult("there"); + }); + int count = 0; + QString res; + Utils::onResultReady(f, [&count, &res](const QString &s) { + ++count; + res = s; + }); + f.waitForFinished(); + QCoreApplication::processEvents(); + QCOMPARE(count, 2); + QCOMPARE(res, QString("there")); + } + { // lambda with guard + QFuture f = Utils::runAsync([](QFutureInterface &fi) { + fi.reportResult("Hi"); + fi.reportResult("there"); + }); + int count = 0; + ObjWithProperty obj; + Utils::onResultReady(f, &obj, [&count, &obj](const QString &s) { + ++count; + obj.setValue(s); + }); + f.waitForFinished(); + QCoreApplication::processEvents(); + QCOMPARE(count, 2); + QCOMPARE(obj.value, QString("there")); + } + { // member + QFuture f = Utils::runAsync([]() { return QString("Hi"); }); + ObjWithProperty obj; + Utils::onResultReady(f, &obj, &ObjWithProperty::setValue); + f.waitForFinished(); + QCoreApplication::processEvents(); + QCOMPARE(obj.value, QString("Hi")); + } +} + QTEST_MAIN(tst_RunExtensions) #include "tst_runextensions.moc" From 137695cae709adf01d20f924b217e70a23f79f05 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 31 Oct 2016 09:29:19 +0100 Subject: [PATCH 31/47] Wizards: Move cmake required version before project line This is apparently necessary to establish policy before setting up things. Task-number: QTCREATORBUG-17197 Change-Id: I8b12e752e05e65b2275c0a97cf1b727f60c88cd0 Reviewed-by: Tim Jenssen --- .../qtcreator/templates/wizards/projects/plainc/CMakeLists.txt | 3 ++- .../templates/wizards/projects/plaincpp/CMakeLists.txt | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt index 9001db70166..a33d87a2173 100644 --- a/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt @@ -1,4 +1,5 @@ -project(%{ProjectName}) cmake_minimum_required(VERSION 2.8) + +project(%{ProjectName}) aux_source_directory(. SRC_LIST) add_executable(${PROJECT_NAME} ${SRC_LIST}) diff --git a/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt index 9001db70166..a33d87a2173 100644 --- a/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt @@ -1,4 +1,5 @@ -project(%{ProjectName}) cmake_minimum_required(VERSION 2.8) + +project(%{ProjectName}) aux_source_directory(. SRC_LIST) add_executable(${PROJECT_NAME} ${SRC_LIST}) From e6d553ce59eaf06c18ce5f6b445620ec5e38e3ab Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Mon, 31 Oct 2016 09:36:44 +0100 Subject: [PATCH 32/47] Wizards: Explicitly list sources in CMakeLists.txt Task-number: QTCREATORBUG-17196 Change-Id: I478f2f945a6f7ee3183aa09871bccc7e475e5501 Reviewed-by: Tim Jenssen --- .../qtcreator/templates/wizards/projects/plainc/CMakeLists.txt | 3 +-- .../templates/wizards/projects/plaincpp/CMakeLists.txt | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt index a33d87a2173..f4783c4195d 100644 --- a/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt @@ -1,5 +1,4 @@ cmake_minimum_required(VERSION 2.8) project(%{ProjectName}) -aux_source_directory(. SRC_LIST) -add_executable(${PROJECT_NAME} ${SRC_LIST}) +add_executable(${PROJECT_NAME} "%{CFileName}") diff --git a/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt index a33d87a2173..6393118931f 100644 --- a/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt @@ -1,5 +1,4 @@ cmake_minimum_required(VERSION 2.8) project(%{ProjectName}) -aux_source_directory(. SRC_LIST) -add_executable(${PROJECT_NAME} ${SRC_LIST}) +add_executable(${PROJECT_NAME} "%{CppFileName}") From f8cf53875e7b24575093e6de1f64bc99663a3e64 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Thu, 27 Oct 2016 17:08:25 +0200 Subject: [PATCH 33/47] Doc: Describe adding vertical guides to QML Profiler timeline Update screenshot and move numbers around, because the time ruler was not described before. Change-Id: I6e13269349b847249ff6b1a9d9c8062ed55bc7f6 Reviewed-by: Ulf Hermann --- .../qtcreator-qml-performance-monitor.png | Bin 21683 -> 23054 bytes doc/src/analyze/qtquick-profiler.qdoc | 12 +++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/doc/images/qtcreator-qml-performance-monitor.png b/doc/images/qtcreator-qml-performance-monitor.png index f8e17dc5e9550dd2e6e1c809ea372da42a422412..6de351818e265c921659b63c78803ea700ca0285 100644 GIT binary patch literal 23054 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 Date: Mon, 31 Oct 2016 10:46:22 +0100 Subject: [PATCH 34/47] Doc: Describe new Diff editor options You can now view unsaved changes in the current file or all open files. Added a subtitle and moved the image to the new section. Change-Id: I8135dc7c9e2edc60b88d84a241f6d959ba590464 Reviewed-by: Jarek Kobus --- doc/src/editors/creator-diff-editor.qdoc | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/doc/src/editors/creator-diff-editor.qdoc b/doc/src/editors/creator-diff-editor.qdoc index 33e6250fb28..b9b16e80d21 100644 --- a/doc/src/editors/creator-diff-editor.qdoc +++ b/doc/src/editors/creator-diff-editor.qdoc @@ -37,22 +37,32 @@ \title Comparing Files - You can use a diff editor from \QC to compare two text files. They can be - either versions of the same file or arbitrary files. + You can use a diff editor to display unsaved changed in the current file or + all open files or to compare any two text files that can be either versions + of the same file or arbitrary files. - \image creator-diff-editor.png "Diff editor output in the Edit mode" + To view unsaved changes in the current file, select \uicontrol Tools > + \uicontrol Diff > \uicontrol {Diff Current File}. - To compare files: + To view unsaved changes in all open files, select \uicontrol Tools > + \uicontrol Diff > \uicontrol {Diff Open Files}. + + To compare two files: \list 1 - \li Select \uicontrol Tools > \uicontrol Diff. + \li Select \uicontrol Tools > \uicontrol Diff > + \uicontrol {Diff External Files}. \li Select two files to compare. \endlist - The differences are output in the \uicontrol Edit mode. Color coding is used + \section1 Viewing the Changes + + \image creator-diff-editor.png "Diff editor output in the Edit mode" + + The changes are displayed in the \uicontrol Edit mode. Color coding is used to mark changed lines. By default, light red indicates lines that contain removed text (painted a darker red) in the left pane and light green indicates lines that contain added text (painted a darker green) in the From 85bcb5b5c7fdd9d5e14577ba475b9bb5dd3a6f32 Mon Sep 17 00:00:00 2001 From: Leena Miettinen Date: Mon, 31 Oct 2016 11:03:17 +0100 Subject: [PATCH 35/47] Doc: Restructure the Diff editor docs Move the instructions for changing the default colors to the end and add a section title. Change-Id: I837e4d25a686d1bf7e9288a438f6321a9ae9d7ed Reviewed-by: Jarek Kobus --- doc/src/editors/creator-diff-editor.qdoc | 38 +++++++++++++----------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/doc/src/editors/creator-diff-editor.qdoc b/doc/src/editors/creator-diff-editor.qdoc index b9b16e80d21..a0286ae8615 100644 --- a/doc/src/editors/creator-diff-editor.qdoc +++ b/doc/src/editors/creator-diff-editor.qdoc @@ -80,6 +80,26 @@ \inlineimage sidebysidediff.png (\uicontrol {Switch to Side by Side Diff Editor}). + To only show text changes, select \uicontrol {Ignore Whitespace}. + + To expand the context for the changes, set the number of unchanged lines to + show in \uicontrol {Context lines}. Set the value to -1 to show the whole + file. + + By default, the horizontal scroll bars in the left and right pane are + synchronized. To use them independently of each other, select the + \inlineimage linkicon.png + (\uicontrol {Synchronize Horizontal Scroll Bars}) button. + + If the files change outside \QC, select \inlineimage reload_gray.png + (\uicontrol {Reload Editor}) to compare them again and to show the results. + + To send a chunk of changes to a \l{Pasting and Fetching Code Snippets} + {code pasting service}, select \uicontrol {Send Chunk to CodePaster} in the + context menu. + + \section1 Changing the Colors + To change the default colors, select \uicontrol Tools > \uicontrol Options > \uicontrol {Text Editor} > \uicontrol {Font & Colors}. Create your own color scheme and select new colors for the following options: @@ -105,22 +125,4 @@ indicates added characters. \endlist - - To only show text changes, select \uicontrol {Ignore Whitespace}. - - To expand the context for the changes, set the number of unchanged lines to - show in \uicontrol {Context lines}. Set the value to -1 to show the whole - file. - - By default, the horizontal scroll bars in the left and right pane are - synchronized. To use them independently of each other, select the - \inlineimage linkicon.png - (\uicontrol {Synchronize Horizontal Scroll Bars}) button. - - If the files change outside \QC, select \inlineimage reload_gray.png - (\uicontrol {Reload Editor}) to compare them again and to show the results. - - To send a chunk of changes to a \l{Pasting and Fetching Code Snippets} - {code pasting service}, select \uicontrol {Send Chunk to CodePaster} in the - context menu. */ From 0c0c0a6fd076fc7666af5f0263965d80fff1da51 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Fri, 28 Oct 2016 15:17:12 +0200 Subject: [PATCH 36/47] Jsonwizard: Modernize JsonFieldPage elements QTCREATORBUG-17190 is fixed by this since initialization is fixed as a side effect;-) Task-number: QTCREATORBUG-17190 Change-Id: I9d1f81d6cca26fcdd9ba8a49ee66e05607d6cae1 Reviewed-by: Orgad Shaneh Reviewed-by: Ulf Hermann --- .../jsonwizard/jsonfieldpage.cpp | 20 ---------- .../jsonwizard/jsonfieldpage_p.h | 39 +++++-------------- 2 files changed, 10 insertions(+), 49 deletions(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp index aeb799ae027..fe49ff41292 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage.cpp @@ -304,9 +304,6 @@ void JsonFieldPage::Field::setIsCompleteExpando(const QVariant &v, const QString // LabelFieldData: // -------------------------------------------------------------------- -LabelField::LabelField() : m_wordWrap(false) -{ } - bool LabelField::parseData(const QVariant &data, QString *errorMessage) { if (data.type() != QVariant::Map) { @@ -343,9 +340,6 @@ QWidget *LabelField::createWidget(const QString &displayName, JsonFieldPage *pag // SpacerFieldData: // -------------------------------------------------------------------- -SpacerField::SpacerField() : m_factor(1) -{ } - bool SpacerField::parseData(const QVariant &data, QString *errorMessage) { if (data.isNull()) @@ -388,9 +382,6 @@ QWidget *SpacerField::createWidget(const QString &displayName, JsonFieldPage *pa // LineEditFieldData: // -------------------------------------------------------------------- -LineEditField::LineEditField() : m_isModified(false), m_isValidating(false) -{ } - bool LineEditField::parseData(const QVariant &data, QString *errorMessage) { if (data.isNull()) @@ -502,9 +493,6 @@ void LineEditField::initializeData(MacroExpander *expander) // -------------------------------------------------------------------- -TextEditField::TextEditField() : m_acceptRichText(false) -{ } - bool TextEditField::parseData(const QVariant &data, QString *errorMessage) { if (data.isNull()) @@ -570,9 +558,6 @@ void TextEditField::initializeData(MacroExpander *expander) // PathChooserFieldData: // -------------------------------------------------------------------- -PathChooserField::PathChooserField() : m_kind(PathChooser::ExistingDirectory) -{ } - bool PathChooserField::parseData(const QVariant &data, QString *errorMessage) { if (data.isNull()) @@ -668,11 +653,6 @@ void PathChooserField::initializeData(MacroExpander *expander) // CheckBoxFieldData: // -------------------------------------------------------------------- -CheckBoxField::CheckBoxField() : - m_checkedValue(QLatin1String("0")), - m_uncheckedValue(QLatin1String("1")) -{ } - bool CheckBoxField::parseData(const QVariant &data, QString *errorMessage) { if (data.isNull()) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h index e02723a5ec6..f79f36d6c69 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h @@ -63,36 +63,28 @@ public: class LabelField : public JsonFieldPage::Field { -public: - LabelField(); - private: QWidget *createWidget(const QString &displayName, JsonFieldPage *page) override; bool parseData(const QVariant &data, QString *errorMessage) override; - bool m_wordWrap; + bool m_wordWrap = false; QString m_text; }; class SpacerField : public JsonFieldPage::Field { public: - SpacerField(); - bool suppressName() const override { return true; } private: bool parseData(const QVariant &data, QString *errorMessage) override; QWidget *createWidget(const QString &displayName, JsonFieldPage *page) override; - int m_factor; + int m_factor = 1; }; class LineEditField : public JsonFieldPage::Field { -public: - LineEditField(); - private: bool parseData(const QVariant &data, QString *errorMessage) override; QWidget *createWidget(const QString &displayName, JsonFieldPage *page) override; @@ -102,10 +94,10 @@ private: bool validate(Utils::MacroExpander *expander, QString *message) override; void initializeData(Utils::MacroExpander *expander) override; - bool m_isModified; - bool m_isValidating; - bool m_restoreLastHistoryItem; - bool m_isPassword; + bool m_isModified = false; + bool m_isValidating = false; + bool m_restoreLastHistoryItem = false; + bool m_isPassword = false; QString m_placeholderText; QString m_defaultText; QString m_disabledText; @@ -117,9 +109,6 @@ private: class TextEditField : public JsonFieldPage::Field { -public: - TextEditField(); - private: bool parseData(const QVariant &data, QString *errorMessage) override; QWidget *createWidget(const QString &displayName, JsonFieldPage *page) override; @@ -130,7 +119,7 @@ private: void initializeData(Utils::MacroExpander *expander) override; QString m_defaultText; - bool m_acceptRichText; + bool m_acceptRichText = false; QString m_disabledText; mutable QString m_currentText; @@ -138,9 +127,6 @@ private: class PathChooserField : public JsonFieldPage::Field { -public: - PathChooserField(); - private: bool parseData(const QVariant &data, QString *errorMessage) override; @@ -155,7 +141,7 @@ private: QString m_path; QString m_basePath; QString m_historyId; - Utils::PathChooser::Kind m_kind; + Utils::PathChooser::Kind m_kind = Utils::PathChooser::ExistingDirectory; QString m_currentPath; }; @@ -163,8 +149,6 @@ private: class CheckBoxField : public JsonFieldPage::Field { public: - CheckBoxField(); - bool suppressName() const override { return true; } private: @@ -177,8 +161,8 @@ private: bool validate(Utils::MacroExpander *expander, QString *message) override; void initializeData(Utils::MacroExpander *expander) override; - QString m_checkedValue; - QString m_uncheckedValue; + QString m_checkedValue = "0"; + QString m_uncheckedValue = "1"; QVariant m_checkedExpression; bool m_isModified = false; @@ -186,9 +170,6 @@ private: class ComboBoxField : public JsonFieldPage::Field { -public: - ComboBoxField() = default; - private: bool parseData(const QVariant &data, QString *errorMessage) override; From cff2ee701d65bec1c29e0234752a10160c1196f8 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 31 Oct 2016 14:16:59 +0100 Subject: [PATCH 37/47] ProjectExplorer: Fix compile with Qt5.6 / gcc 4.8 Change-Id: Id1ded1679e9cde4e9cabba61dc5e6aa7aea1e7ed Reviewed-by: Orgad Shaneh --- src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h index f79f36d6c69..13cab66ccfe 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h +++ b/src/plugins/projectexplorer/jsonwizard/jsonfieldpage_p.h @@ -161,8 +161,8 @@ private: bool validate(Utils::MacroExpander *expander, QString *message) override; void initializeData(Utils::MacroExpander *expander) override; - QString m_checkedValue = "0"; - QString m_uncheckedValue = "1"; + QString m_checkedValue = QString("0"); + QString m_uncheckedValue = QString("1"); QVariant m_checkedExpression; bool m_isModified = false; From 4325f4facb0973529fe70318c451abfed0230195 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 31 Oct 2016 15:40:20 +0200 Subject: [PATCH 38/47] QmakePM: Avoid soft assertion ... when a matching toolchain is not found. Change-Id: I901bdb51f98a88b2402b12309a05e0bc5ffcaa3b Reviewed-by: Tobias Hunger --- src/plugins/qmakeprojectmanager/qmakekitinformation.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp index 79fb5786588..a97ecc68add 100644 --- a/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp +++ b/src/plugins/qmakeprojectmanager/qmakekitinformation.cpp @@ -87,7 +87,8 @@ void QmakeKitInformation::setup(Kit *k) break; } } - ToolChainKitInformation::setToolChain(k, possibleTc); + if (possibleTc) + ToolChainKitInformation::setToolChain(k, possibleTc); } } From d012e3e4bd444063e2a506ee781fb2e7be149e01 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 31 Oct 2016 14:23:05 +0100 Subject: [PATCH 39/47] Clarify section about broken performance counters on i.MX6 The performance counters are broken on most (all?) i.MX6 boards, not only on the ones from Boundary Devices. Task-number: QTBUG-56769 Change-Id: I9e0f291be7e00df3d9d1b98c7414dfd37e265b39 Reviewed-by: Kari Hormi Reviewed-by: Leena Miettinen --- doc/src/analyze/cpu-usage-analyzer.qdoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/src/analyze/cpu-usage-analyzer.qdoc b/doc/src/analyze/cpu-usage-analyzer.qdoc index 873abff8c08..dddea53102f 100644 --- a/doc/src/analyze/cpu-usage-analyzer.qdoc +++ b/doc/src/analyze/cpu-usage-analyzer.qdoc @@ -346,11 +346,11 @@ \li Some versions of Perf will not start recording unless given a certain minimum sampling frequency. Try with a \uicontrol {Sampling Frequency} of 1000. - \li On some devices, for example Boundary Devices i.MX6 Boards, the - Perf support is not very stable and the Linux kernel may randomly - fail to record data after some time. Perf can use different types - of events to trigger samples. You can get a list of available event - types by running \c {perf list} on the device and add + \li On some devices, in particular various i.MX6 Boards, the hardware + performance counters are dysfunctional and the Linux kernel may + randomly fail to record data after some time. Perf can use different + types of events to trigger samples. You can get a list of available + event types by running \c {perf list} on the device and add \c {-e } to the \uicontrol {Additional arguments} field to change the event type to be used. The choice of event type affects the performance and stability of the sampling. From 457cfcfae98f81a3a1c45a451a6e77345a4d023b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 31 Oct 2016 14:32:47 +0100 Subject: [PATCH 40/47] Welcome: Fix that filter string was cleared when changing page In examples and tutorials pages. Since the pages are unloaded and loaded again when the tab changes, they loose their internal state and require the search text to be kept as state in the model (which makes sense anyhow). Task-number: QTCREATORBUG-15901 Change-Id: I4fb05ca47f8337008c51e17cc95962a5e9e67fef Reviewed-by: Thomas Hartmann --- share/qtcreator/welcomescreen/examples.qml | 4 +-- share/qtcreator/welcomescreen/tutorials.qml | 4 +-- src/plugins/qtsupport/exampleslistmodel.cpp | 34 ++++++++++++++++++--- src/plugins/qtsupport/exampleslistmodel.h | 31 ++++++------------- 4 files changed, 44 insertions(+), 29 deletions(-) diff --git a/share/qtcreator/welcomescreen/examples.qml b/share/qtcreator/welcomescreen/examples.qml index 063a1f5a49b..99476d8817b 100644 --- a/share/qtcreator/welcomescreen/examples.qml +++ b/share/qtcreator/welcomescreen/examples.qml @@ -66,9 +66,9 @@ Item { anchors.leftMargin: 18 anchors.rightMargin: 20 anchors.right: parent.right - + text: examplesModel.searchString placeholderText: qsTr("Search in Examples...") - onTextChanged: examplesModel.parseSearchString(text) + onTextChanged: examplesModel.setSearchString(text) } CustomizedGridView { diff --git a/share/qtcreator/welcomescreen/tutorials.qml b/share/qtcreator/welcomescreen/tutorials.qml index 4c8535bedb6..eb227bf5117 100644 --- a/share/qtcreator/welcomescreen/tutorials.qml +++ b/share/qtcreator/welcomescreen/tutorials.qml @@ -39,9 +39,9 @@ Item { anchors.rightMargin: 20 anchors.left: parent.left anchors.leftMargin: 30 - + text: tutorialsModel.searchString placeholderText: qsTr("Search in Tutorials...") - onTextChanged: tutorialsModel.parseSearchString(text) + onTextChanged: tutorialsModel.setSearchString(text) } CustomizedGridView { diff --git a/src/plugins/qtsupport/exampleslistmodel.cpp b/src/plugins/qtsupport/exampleslistmodel.cpp index 83a7256e6a9..ac2fd0d36ab 100644 --- a/src/plugins/qtsupport/exampleslistmodel.cpp +++ b/src/plugins/qtsupport/exampleslistmodel.cpp @@ -760,6 +760,14 @@ void ExamplesListModelFilter::updateFilter() } } +void ExamplesListModelFilter::setFilterStrings(const QStringList &arg) +{ + if (m_filterStrings != arg) { + m_filterStrings = arg; + delayedUpdateFilter(); + } +} + bool containsSubString(const QStringList &list, const QString &substr, Qt::CaseSensitivity cs) { return Utils::contains(list, [&substr, &cs](const QString &elem) { @@ -789,11 +797,11 @@ bool ExamplesListModelFilter::filterAcceptsRow(int sourceRow, const QModelIndex }); } - if (!m_searchString.isEmpty()) { + if (!m_filterStrings.isEmpty()) { const QString description = sourceModel()->index(sourceRow, 0, sourceParent).data(Description).toString(); const QString name = sourceModel()->index(sourceRow, 0, sourceParent).data(Name).toString(); - foreach (const QString &subString, m_searchString) { + foreach (const QString &subString, m_filterStrings) { bool wordMatch = false; wordMatch |= (bool)name.contains(subString, Qt::CaseInsensitive); if (wordMatch) @@ -835,6 +843,14 @@ void ExamplesListModelFilter::filterForExampleSet(int index) m_sourceModel->selectExampleSet(index); } +void ExamplesListModelFilter::setFilterTags(const QStringList &arg) +{ + if (m_filterTags != arg) { + m_filterTags = arg; + emit filterTagsChanged(arg); + } +} + void ExamplesListModelFilter::setShowTutorialsOnly(bool showTutorialsOnly) { m_showTutorialsOnly = showTutorialsOnly; @@ -984,8 +1000,13 @@ struct SearchStringLexer } }; -void ExamplesListModelFilter::parseSearchString(const QString &arg) +void ExamplesListModelFilter::setSearchString(const QString &arg) { + if (m_searchString == arg) + return; + m_searchString = arg; + emit searchStringChanged(m_searchString); + // parse and update QStringList tags; QStringList searchTerms; SearchStringLexer lex(arg); @@ -1007,10 +1028,15 @@ void ExamplesListModelFilter::parseSearchString(const QString &arg) } } - setSearchStrings(searchTerms); + setFilterStrings(searchTerms); setFilterTags(tags); delayedUpdateFilter(); } +QString ExamplesListModelFilter::searchString() const +{ + return m_searchString; +} + } // namespace Internal } // namespace QtSupport diff --git a/src/plugins/qtsupport/exampleslistmodel.h b/src/plugins/qtsupport/exampleslistmodel.h index cc1f9a735f0..522bd92624e 100644 --- a/src/plugins/qtsupport/exampleslistmodel.h +++ b/src/plugins/qtsupport/exampleslistmodel.h @@ -163,7 +163,7 @@ class ExamplesListModelFilter : public QSortFilterProxyModel public: Q_PROPERTY(bool showTutorialsOnly READ showTutorialsOnly WRITE setShowTutorialsOnly NOTIFY showTutorialsOnlyChanged) Q_PROPERTY(QStringList filterTags READ filterTags WRITE setFilterTags NOTIFY filterTagsChanged) - Q_PROPERTY(QStringList searchStrings READ searchStrings WRITE setSearchStrings NOTIFY searchStrings) + Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY searchStringChanged) Q_PROPERTY(int exampleSetIndex READ exampleSetIndex NOTIFY exampleSetIndexChanged) @@ -171,9 +171,11 @@ public: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const; + Q_INVOKABLE void setSearchString(const QString &arg); + QString searchString() const; + bool showTutorialsOnly() { return m_showTutorialsOnly; } QStringList filterTags() const { return m_filterTags; } - QStringList searchStrings() const { return m_searchString; } int rowCount(const QModelIndex &parent = QModelIndex()) const; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; @@ -182,35 +184,21 @@ public: Q_INVOKABLE void filterForExampleSet(int index); public slots: - void setFilterTags(const QStringList &arg) - { - if (m_filterTags != arg) { - m_filterTags = arg; - emit filterTagsChanged(arg); - } - } + void setFilterTags(const QStringList &arg); void updateFilter(); - void setSearchStrings(const QStringList &arg) - { - if (m_searchString != arg) { - m_searchString = arg; - emit searchStrings(arg); - delayedUpdateFilter(); - } - } - - void parseSearchString(const QString &arg); void setShowTutorialsOnly(bool showTutorialsOnly); void handleQtVersionsChanged(); signals: void showTutorialsOnlyChanged(); void filterTagsChanged(const QStringList &arg); - void searchStrings(const QStringList &arg); + void searchStringChanged(const QString &arg); void exampleSetIndexChanged(); private: + void setFilterStrings(const QStringList &arg); + void qtVersionManagerLoaded(); void helpManagerInitialized(); @@ -221,8 +209,9 @@ private: int exampleSetIndex() const; bool m_showTutorialsOnly; + QString m_searchString; QStringList m_filterTags; - QStringList m_searchString; + QStringList m_filterStrings; ExamplesListModel *m_sourceModel; int m_timerId; bool m_blockIndexUpdate; From f952c3ee4a2a7f1560a1718c29967bc181a5bba2 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Mon, 31 Oct 2016 14:34:32 +0100 Subject: [PATCH 41/47] QmlDesigner: Fallback to create types from source We fallback to create types from source, if other means failed. This can be required if the meta info is incomplete/incorrect when a C++ type is mocked. Change-Id: I50d45a6f9d7eba3483da10d9e1d7d6644d9aeb96 Reviewed-by: Tim Jenssen --- .../instances/objectnodeinstance.cpp | 28 ++++++++++++++++++- .../qml2puppet/instances/objectnodeinstance.h | 1 + 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp index c3d0437bf6a..6bd10a2e0b8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.cpp @@ -605,7 +605,33 @@ ObjectNodeInstance::Pointer ObjectNodeInstance::create(QObject *object) QObject *ObjectNodeInstance::createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context) { - return QmlPrivateGate::createPrimitive(typeName, majorNumber, minorNumber, context); + QObject *object = QmlPrivateGate::createPrimitive(typeName, majorNumber, minorNumber, context); + + /* Let's try to create the primitive from source, since with incomplete meta info this might be a pure + * QML type. This is the case for example if a C++ type is mocked up with a QML file. + */ + + if (!object) + object = createPrimitiveFromSource(typeName, majorNumber, minorNumber, context); + + return object; +} + +QObject *ObjectNodeInstance::createPrimitiveFromSource(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context) +{ + if (typeName.isEmpty()) + return 0; + + QStringList parts = typeName.split("/"); + const QString unqualifiedTypeName = parts.last(); + parts.removeLast(); + + if (parts.isEmpty()) + return 0; + + const QString importString = parts.join(".") + " " + QString::number(majorNumber) + "." + QString::number(minorNumber); + QString source = "import " + importString + "\n" + unqualifiedTypeName + " {\n" + "}\n"; + return createCustomParserObject(source, "", context); } QObject *ObjectNodeInstance::createComponentWrap(const QString &nodeSource, const QByteArray &importCode, QQmlContext *context) diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h index cecc9c8ee3c..8266f0addf8 100644 --- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h +++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/objectnodeinstance.h @@ -67,6 +67,7 @@ public: static Pointer create(QObject *objectToBeWrapped); static QObject *createPrimitive(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context); + static QObject *createPrimitiveFromSource(const QString &typeName, int majorNumber, int minorNumber, QQmlContext *context); static QObject *createCustomParserObject(const QString &nodeSource, const QByteArray &importCode, QQmlContext *context); static QObject *createComponent(const QString &componentPath, QQmlContext *context); static QObject *createComponent(const QUrl &componentUrl, QQmlContext *context); From 6e6d5b53091d598478c90669d85af25136cc2ea5 Mon Sep 17 00:00:00 2001 From: Nikolai Kosjar Date: Thu, 20 Oct 2016 13:18:54 +0200 Subject: [PATCH 42/47] ClangStaticAnalyzer: Tests: Rely on projects telling when they finished parsing We relied on the CppModelManager to tell us whether a project was reparsed after a kit change. While this worked, it was not guaranteed that the project is really finished (and ready for e.g. building) after pushing new ProjectInfos to the CppModelManager. Rely on the projects telling when they are finished with parsing. This is more accurate and future-proof. The introduced signals in Project and SessionManager are (at the moment) only for tests. Change-Id: I1b368ec4585ffa8755eb28fac6d187cce31243ee Reviewed-by: Tobias Hunger Reviewed-by: Christian Kandeler --- .../appmanager/project/appmanagerproject.cpp | 2 + .../autotoolsproject.cpp | 2 + ...taticanalyzerpreconfiguredsessiontests.cpp | 61 +++++++++++++------ .../cmakeprojectmanager/cmakeproject.cpp | 2 + .../genericprojectmanager/genericproject.cpp | 1 + src/plugins/nim/project/nimproject.cpp | 2 + src/plugins/projectexplorer/project.h | 3 + .../projectexplorer/projectexplorer.cpp | 3 + src/plugins/projectexplorer/session.h | 3 + .../pythoneditor/pythoneditorplugin.cpp | 2 + src/plugins/qbsprojectmanager/qbsproject.cpp | 1 + .../qmakeprojectmanager/qmakeproject.cpp | 1 + src/plugins/qmlprojectmanager/qmlproject.cpp | 2 + 13 files changed, 68 insertions(+), 17 deletions(-) diff --git a/src/plugins/appmanager/project/appmanagerproject.cpp b/src/plugins/appmanager/project/appmanagerproject.cpp index 9f79be2e63f..d0ea2824d41 100644 --- a/src/plugins/appmanager/project/appmanagerproject.cpp +++ b/src/plugins/appmanager/project/appmanagerproject.cpp @@ -129,6 +129,8 @@ void AppManagerProject::populateProject() foreach (ProjectExplorer::Target *target, targets()) targetUpdateDeployableFiles(target, files); } + + emit parsingFinished(); } void AppManagerProject::recursiveScanDirectory(const QDir &dir, QSet &container) diff --git a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp index b66b37c1067..d07d3552343 100644 --- a/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp +++ b/src/plugins/autotoolsprojectmanager/autotoolsproject.cpp @@ -231,6 +231,8 @@ void AutotoolsProject::makefileParsingFinished() m_makefileParserThread->deleteLater(); m_makefileParserThread = 0; + + emit parsingFinished(); } void AutotoolsProject::onFileChanged(const QString &file) diff --git a/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp b/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp index 462e26fe836..e6ae1404be2 100644 --- a/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp +++ b/src/plugins/clangstaticanalyzer/clangstaticanalyzerpreconfiguredsessiontests.cpp @@ -29,7 +29,6 @@ #include "clangstaticanalyzertool.h" #include "clangstaticanalyzerutils.h" -#include #include #include #include @@ -44,6 +43,7 @@ #include #include #include +#include #include @@ -66,6 +66,35 @@ static bool processEventsUntil(const std::function condition, int timeOu } } +class WaitForParsedProjects : public QObject +{ +public: + WaitForParsedProjects(ProjectExplorer::SessionManager &sessionManager, + const QStringList &projects) + : m_sessionManager(sessionManager) + , m_projectsToWaitFor(projects) + { + connect(&m_sessionManager, &ProjectExplorer::SessionManager::projectFinishedParsing, + this, &WaitForParsedProjects::onProjectFinishedParsing); + } + + void onProjectFinishedParsing(ProjectExplorer::Project *project) + { + m_projectsToWaitFor.removeOne(project->projectFilePath().toString()); + } + + bool wait() + { + return processEventsUntil([this]() { + return m_projectsToWaitFor.isEmpty(); + }); + } + +private: + ProjectExplorer::SessionManager &m_sessionManager; + QStringList m_projectsToWaitFor; +}; + namespace ClangStaticAnalyzer { namespace Internal { @@ -84,16 +113,14 @@ void ClangStaticAnalyzerPreconfiguredSessionTests::initTestCase() if (!m_sessionManager.sessions().contains(preconfiguredSessionName)) QSKIP("Manually preconfigured session 'ClangStaticAnalyzerPreconfiguredSession' needed."); - // Load session - if (m_sessionManager.activeSession() != preconfiguredSessionName) - QVERIFY(m_sessionManager.loadSession(preconfiguredSessionName)); + if (m_sessionManager.activeSession() == preconfiguredSessionName) + QSKIP("Session must not be already active."); - // Wait until all projects are loaded. - const int sessionManagerProjects = m_sessionManager.projects().size(); - const auto allProjectsLoaded = [sessionManagerProjects]() { - return CppModelManager::instance()->projectInfos().size() == sessionManagerProjects; - }; - QVERIFY(processEventsUntil(allProjectsLoaded)); + // Load session + const QStringList projects = m_sessionManager.projectsForSessionName(preconfiguredSessionName); + WaitForParsedProjects waitForParsedProjects(m_sessionManager, projects); + QVERIFY(m_sessionManager.loadSession(preconfiguredSessionName)); + QVERIFY(waitForParsedProjects.wait()); } void ClangStaticAnalyzerPreconfiguredSessionTests::testPreconfiguredSession() @@ -201,15 +228,15 @@ bool ClangStaticAnalyzerPreconfiguredSessionTests::switchToProjectAndTarget(Proj m_sessionManager.setStartupProject(project); if (target != project->activeTarget()) { - QSignalSpy waitUntilProjectUpdated(CppModelManager::instance(), - &CppModelManager::projectPartsUpdated); + QSignalSpy spyFinishedParsing(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::projectFinishedParsing); m_sessionManager.setActiveTarget(project, target, ProjectExplorer::SetActive::NoCascade); + QTC_ASSERT(spyFinishedParsing.wait(30000), return false); - const bool waitResult = waitUntilProjectUpdated.wait(30000); - if (!waitResult) { - qWarning() << "waitUntilProjectUpdated() failed"; - return false; - } + const QVariant projectArgument = spyFinishedParsing.takeFirst().takeFirst(); + QTC_ASSERT(projectArgument.canConvert(), return false); + + return projectArgument.value() == project; } return true; diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 50dd058368f..52905ad598d 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -145,6 +145,8 @@ void CMakeProject::updateProjectData() emit fileListChanged(); emit cmakeBc->emitBuildTypeChanged(); + + emit parsingFinished(); } void CMakeProject::updateQmlJSCodeModel() diff --git a/src/plugins/genericprojectmanager/genericproject.cpp b/src/plugins/genericprojectmanager/genericproject.cpp index 8ccd1793377..e33d20dd943 100644 --- a/src/plugins/genericprojectmanager/genericproject.cpp +++ b/src/plugins/genericprojectmanager/genericproject.cpp @@ -286,6 +286,7 @@ void GenericProject::refresh(RefreshOptions options) } refreshCppCodeModel(); + emit parsingFinished(); } /** diff --git a/src/plugins/nim/project/nimproject.cpp b/src/plugins/nim/project/nimproject.cpp index 2f57238ef61..eb0829e7a68 100644 --- a/src/plugins/nim/project/nimproject.cpp +++ b/src/plugins/nim/project/nimproject.cpp @@ -112,6 +112,8 @@ void NimProject::populateProject() rootProjectNode()->buildTree(fileNodes); emit fileListChanged(); + + emit parsingFinished(); } void NimProject::recursiveScanDirectory(const QDir &dir, QSet &container) diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index f7dbc037c75..7f636f8ad81 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -168,6 +168,9 @@ signals: void projectContextUpdated(); void projectLanguagesUpdated(); +signals: // for tests only + void parsingFinished(); + protected: virtual RestoreResult fromMap(const QVariantMap &map, QString *errorMessage); virtual bool setupTarget(Target *t); diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp index a441ca87c5b..6c9d6ab557e 100644 --- a/src/plugins/projectexplorer/projectexplorer.cpp +++ b/src/plugins/projectexplorer/projectexplorer.cpp @@ -1684,6 +1684,9 @@ ProjectExplorerPlugin::OpenProjectResult ProjectExplorerPlugin::openProjects(con foundProjectManager = true; QString tmp; if (Project *pro = manager->openProject(filePath, &tmp)) { + QObject::connect(pro, &Project::parsingFinished, [pro]() { + emit SessionManager::instance()->projectFinishedParsing(pro); + }); QString restoreError; Project::RestoreResult restoreResult = pro->restoreSettings(&restoreError); if (restoreResult == Project::RestoreResult::Ok) { diff --git a/src/plugins/projectexplorer/session.h b/src/plugins/projectexplorer/session.h index 0680c6e40ea..0b8aebdc5cd 100644 --- a/src/plugins/projectexplorer/session.h +++ b/src/plugins/projectexplorer/session.h @@ -138,6 +138,9 @@ signals: void aboutToSaveSession(); void dependencyChanged(ProjectExplorer::Project *a, ProjectExplorer::Project *b); +signals: // for tests only + void projectFinishedParsing(ProjectExplorer::Project *project); + private: static void saveActiveMode(Core::Id mode); void clearProjectFileCache(); diff --git a/src/plugins/pythoneditor/pythoneditorplugin.cpp b/src/plugins/pythoneditor/pythoneditorplugin.cpp index 7d5ede86fde..a2453ad45b1 100644 --- a/src/plugins/pythoneditor/pythoneditorplugin.cpp +++ b/src/plugins/pythoneditor/pythoneditorplugin.cpp @@ -619,6 +619,8 @@ void PythonProject::refresh() return new PythonFileNode(FileName::fromString(f), displayName); }); rootProjectNode()->buildTree(fileNodes); + + emit parsingFinished(); } /** diff --git a/src/plugins/qbsprojectmanager/qbsproject.cpp b/src/plugins/qbsprojectmanager/qbsproject.cpp index 8260547a71e..002fbdaba71 100644 --- a/src/plugins/qbsprojectmanager/qbsproject.cpp +++ b/src/plugins/qbsprojectmanager/qbsproject.cpp @@ -503,6 +503,7 @@ void QbsProject::handleQbsParsingDone(bool success) if (dataChanged) updateAfterParse(); emit projectParsingDone(success); + emit parsingFinished(); } void QbsProject::handleRuleExecutionDone() diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index db652823cc1..11af8907631 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -753,6 +753,7 @@ void QmakeProject::decrementPendingEvaluateFutures() activeTarget()->updateDefaultDeployConfigurations(); updateRunConfigurations(); emit proFilesEvaluated(); + emit parsingFinished(); if (debug) qDebug()<<" Setting state to Base"; } diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp index b7d5552a8af..b8ab17a24df 100644 --- a/src/plugins/qmlprojectmanager/qmlproject.cpp +++ b/src/plugins/qmlprojectmanager/qmlproject.cpp @@ -198,6 +198,8 @@ void QmlProject::refresh(RefreshOptions options) QmlJS::Dialect::Qml); modelManager()->updateProjectInfo(projectInfo, this); + + emit parsingFinished(); } QStringList QmlProject::convertToAbsoluteFiles(const QStringList &paths) const From 49c6710b42d49a29b13ea978af710adb73ba3e8d Mon Sep 17 00:00:00 2001 From: Lorenz Haas Date: Sun, 23 Oct 2016 19:42:55 +0200 Subject: [PATCH 43/47] CppEditor: Fix GenerateGetterSetter for reference types Change-Id: Iad332cf023c6bff0c7f5ae46fb56f0393c9c7b29 Reviewed-by: Orgad Shaneh Reviewed-by: Nikolai Kosjar --- src/plugins/cppeditor/cppquickfix_test.cpp | 60 ++++++++++++++++++++++ src/plugins/cppeditor/cppquickfixes.cpp | 6 ++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 7d51e66414e..3434f87b72d 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -771,6 +771,66 @@ void CppEditorPlugin::test_quickfix_data() "}\n" ); + // Checks: No special treatment for reference to non const. + QTest::newRow("GenerateGetterSetter_referenceToNonConst") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( + "\n" + "class Something\n" + "{\n" + " int &it@;\n" + "};\n" + ) << _( + "\n" + "class Something\n" + "{\n" + " int ⁢\n" + "\n" + "public:\n" + " int &getIt() const;\n" + " void setIt(const int &value);\n" + "};\n" + "\n" + "int &Something::getIt() const\n" + "{\n" + " return it;\n" + "}\n" + "\n" + "void Something::setIt(const int &value)\n" + "{\n" + " it = value;\n" + "}\n" + ); + + // Checks: No special treatment for reference to const. + QTest::newRow("GenerateGetterSetter_referenceToConst") + << CppQuickFixFactoryPtr(new GenerateGetterSetter) << _( + "\n" + "class Something\n" + "{\n" + " const int &it@;\n" + "};\n" + ) << _( + "\n" + "class Something\n" + "{\n" + " const int ⁢\n" + "\n" + "public:\n" + " const int &getIt() const;\n" + " void setIt(const int &value);\n" + "};\n" + "\n" + "const int &Something::getIt() const\n" + "{\n" + " return it;\n" + "}\n" + "\n" + "void Something::setIt(const int &value)\n" + "{\n" + " it = value;\n" + "}\n" + ); + // Checks: // 1. Setter: Setter is a static function. // 2. Getter: Getter is a static, non const function. diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index b7923d7217e..6fd02fd873a 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -3018,10 +3018,12 @@ public: if (passByValue) { paramString = oo.prettyType(fullySpecifiedType, paramName); } else { - FullySpecifiedType constParamType(fullySpecifiedType); + const ReferenceType *refType = type->asReferenceType(); + FullySpecifiedType constParamType(refType ? refType->elementType() + : fullySpecifiedType); constParamType.setConst(true); QScopedPointer referenceType(new ReferenceType(constParamType, false)); - FullySpecifiedType referenceToConstParamType(referenceType.data()); + const FullySpecifiedType referenceToConstParamType(referenceType.data()); paramString = oo.prettyType(referenceToConstParamType, paramName); } From 3c43c35167cfcb807602442a76011f3737696e1e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 21 Oct 2016 18:59:36 +0200 Subject: [PATCH 44/47] remove pretenses of support for DEPLOYMENT with .sources since fa6d0f1231, DEPLOYMENT is aliased to INSTALLS, so we would have to actually look for .sources in entries listed in that variable, which we didn't. apparently, nobody noticed, among other things possibly because the qt4 variant already supports .files in later versions. also, our actual deployment code doesn't use .sources, either. Change-Id: I990240716817118047fc9aa97eff55305fcf7eca Reviewed-by: Tobias Hunger Reviewed-by: Christian Kandeler --- .../qmakeprojectmanager/qmakenodes.cpp | 23 ++++--------------- src/plugins/qmakeprojectmanager/qmakenodes.h | 2 +- 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index 0f588c7a55c..3507ba80b85 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -199,7 +199,6 @@ public: QtSupport::ProFileReader *readerCumulative; ProFileGlobals *qmakeGlobals; QMakeVfs *qmakeVfs; - bool isQt5; }; class PriFileEvalResult @@ -639,7 +638,7 @@ PriFileEvalResult QmakePriFileNode::extractValues(const EvalInput &input, // all the files from those folders and add watchers for them. That's too // dangerous if we get the folders wrong and enumerate the whole project // tree multiple times. - QStringList dynamicVariables = dynamicVarNames(input.readerExact, input.isQt5); + QStringList dynamicVariables = dynamicVarNames(input.readerExact); foreach (ProFile *includeFileExact, includeFilesExact) foreach (const QString &dynamicVar, dynamicVariables) result.folders += input.readerExact->values(dynamicVar, includeFileExact); @@ -1461,25 +1460,15 @@ QStringList QmakePriFileNode::varNamesForRemoving() return vars; } -QStringList QmakePriFileNode::dynamicVarNames(QtSupport::ProFileReader *readerExact, - bool isQt5) +QStringList QmakePriFileNode::dynamicVarNames(QtSupport::ProFileReader *reader) { QStringList result; - // Figure out DEPLOYMENT and INSTALLS - const QString deployment = QLatin1String("DEPLOYMENT"); - const QString sources = QLatin1String(isQt5 ? ".files" : ".sources"); - QStringList listOfVars = readerExact->values(deployment); - foreach (const QString &var, listOfVars) { - result << (var + sources); - } - + // Figure out INSTALLS (and DEPLOYMENT, as it's aliased) const QString installs = QLatin1String("INSTALLS"); const QString files = QLatin1String(".files"); - listOfVars = readerExact->values(installs); - foreach (const QString &var, listOfVars) { + foreach (const QString &var, reader->values(installs)) result << (var + files); - } result.removeDuplicates(); return result; } @@ -1792,10 +1781,6 @@ EvalInput QmakeProFileNode::evalInput() const input.buildDirectory = buildDir(); input.readerExact = m_readerExact; input.readerCumulative = m_readerCumulative; - Target *t = m_project->activeTarget(); - Kit *k = t ? t->kit() : KitManager::defaultKit(); - QtSupport::BaseQtVersion *qtVersion = QtSupport::QtKitInformation::qtVersion(k); - input.isQt5 = !qtVersion || qtVersion->qtVersion() >= QtSupport::QtVersionNumber(5,0,0); input.qmakeGlobals = m_project->qmakeGlobals(); input.qmakeVfs = m_project->qmakeVfs(); return input; diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h index 1bb881f482a..5a1568e0d8e 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.h +++ b/src/plugins/qmakeprojectmanager/qmakenodes.h @@ -180,7 +180,7 @@ protected: static QStringList varNames(ProjectExplorer::FileType type, QtSupport::ProFileReader *readerExact); static QStringList varNamesForRemoving(); static QString varNameForAdding(const QString &mimeType); - static QStringList dynamicVarNames(QtSupport::ProFileReader *readerExact, bool isQt5); + static QStringList dynamicVarNames(QtSupport::ProFileReader *readerExact); static QSet filterFilesProVariables(ProjectExplorer::FileType fileType, const QSet &files); static QSet filterFilesRecursiveEnumerata(ProjectExplorer::FileType fileType, const QSet &files); From fde9758fcba78d3371063883be7cb355f15903e5 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Fri, 21 Oct 2016 21:08:01 +0200 Subject: [PATCH 45/47] prune dead code surrounding isDeployable no-one ever queried this state since S60 support was removed in ae23d50576 (2012). Change-Id: I3e05d90bb43514b4c326e124834cf9c5e89a0168 Reviewed-by: Tobias Hunger Reviewed-by: Christian Kandeler --- .../qmakeprojectmanager/qmakenodes.cpp | 20 ------------------- src/plugins/qmakeprojectmanager/qmakenodes.h | 3 --- 2 files changed, 23 deletions(-) diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.cpp b/src/plugins/qmakeprojectmanager/qmakenodes.cpp index 3507ba80b85..878553e96b3 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodes.cpp @@ -237,7 +237,6 @@ public: TargetInformation targetInformation; InstallsList installsList; QHash newVarValues; - bool isDeployable; QStringList errors; }; @@ -1614,11 +1613,6 @@ QByteArray QmakeProFileNode::cxxDefines() const return result; } -bool QmakeProFileNode::isDeployable() const -{ - return m_isDeployable; -} - /*! \class QmakeProFileNode Implements abstract ProjectNode class @@ -1991,19 +1985,6 @@ EvalResult *QmakeProFileNode::evaluate(const EvalInput &input) result->newVarValues[QmakeCc] = input.readerExact->values("QMAKE_CC"); result->newVarValues[QmakeCxx] = input.readerExact->values("QMAKE_CXX"); - result->isDeployable = false; - if (result->projectType == ApplicationTemplate) { - result->isDeployable = true; - } else { - foreach (const QString &item, input.readerExact->values(QLatin1String("DEPLOYMENT"))) { - if (!input.readerExact->values(item + QLatin1String(".sources")).isEmpty()) { - result->isDeployable = true; - break; - } - } - } - - if (readerBuildPass && readerBuildPass != input.readerExact) delete readerBuildPass; } @@ -2253,7 +2234,6 @@ void QmakeProFileNode::applyEvaluate(EvalResult *evalResult) m_subProjectsNotToDeploy = result->subProjectsNotToDeploy; m_installsList = result->installsList; - m_isDeployable = result->isDeployable; if (m_varValues != result->newVarValues) m_varValues = result->newVarValues; diff --git a/src/plugins/qmakeprojectmanager/qmakenodes.h b/src/plugins/qmakeprojectmanager/qmakenodes.h index 5a1568e0d8e..32d3034470a 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodes.h +++ b/src/plugins/qmakeprojectmanager/qmakenodes.h @@ -354,7 +354,6 @@ public: QString objectExtension() const; QString objectsDirectory() const; QByteArray cxxDefines() const; - bool isDeployable() const; enum AsyncUpdateDelay { ParseNow, ParseLater }; void scheduleUpdate(AsyncUpdateDelay delay); @@ -401,8 +400,6 @@ private: static TargetInformation targetInformation(QtSupport::ProFileReader *reader, QtSupport::ProFileReader *readerBuildPass, const QString &buildDir, const QString &projectFilePath); static InstallsList installsList(const QtSupport::ProFileReader *reader, const QString &projectFilePath, const QString &projectDir); - bool m_isDeployable = false; - bool m_validParse = false; bool m_parseInProgress = true; From 4f7821a71fce60bc08252cc2011956ce7faeae4f Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 31 Oct 2016 14:05:54 +0100 Subject: [PATCH 46/47] Debugger: Disable Nim dumper auto test Needs manual testing in the common case that the intended crash does not occur. Change-Id: I99de4f466df9e3a470a6bcb98b819d15da3a7067 Reviewed-by: hjk --- tests/auto/debugger/tst_dumpers.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/auto/debugger/tst_dumpers.cpp b/tests/auto/debugger/tst_dumpers.cpp index d9f3ac2bd55..c048d893aba 100644 --- a/tests/auto/debugger/tst_dumpers.cpp +++ b/tests/auto/debugger/tst_dumpers.cpp @@ -6221,6 +6221,7 @@ void tst_Dumpers::dumper_data() + Check("v15", "\"utf16\"", "@QJSValue (QString)") + Check("v15.1", "[1]", "116", "@QChar"); +#if 0 #ifdef Q_OS_LINUX // Hint: To open a failing test in Creator, do: // touch qt_tst_dumpers_Nim_.../dummy.nimproject @@ -6229,6 +6230,7 @@ void tst_Dumpers::dumper_data() nimData.configTest = "which nim"; nimData.allProfile = "CONFIG -= qt\n" + "SOURCES += main.nim\n" "# Prevents linking\n" "TARGET=\n" "# Overwrites qmake-generated 'all' target.\n" @@ -6243,8 +6245,10 @@ void tst_Dumpers::dumper_data() "proc mainProc =\n" " var name: string = \"Hello World\"\n" " var i: int = 43\n" + " var j: int\n" " var x: seq[int]\n" " x = @[1, 2, 3, 4, 5, 6]\n\n" + " j = i + name.len()\n" " # Crash it.\n" " var m1 = Mirror(tag:1)\n" " var m2 = Mirror(tag:2)\n" @@ -6268,6 +6272,7 @@ void tst_Dumpers::dumper_data() + Check("x", "<6 items>", Pattern("TY.*NI.6..")) // Something like "TY95019 (NI[6])" + Check("x.2", "[2]", "3", "NI"); #endif +#endif } int main(int argc, char *argv[]) From f582c6a5a6226b4ca949e3f65db17f9d21b780e6 Mon Sep 17 00:00:00 2001 From: hjk Date: Mon, 31 Oct 2016 14:14:16 +0100 Subject: [PATCH 47/47] Debugger: Add a dumper for std::pair Change-Id: I22b644dab9ed27d650b1e99e08f0335f7d265dfd Reviewed-by: hjk --- share/qtcreator/debugger/stdtypes.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/share/qtcreator/debugger/stdtypes.py b/share/qtcreator/debugger/stdtypes.py index 4c8c2cb7545..a1b5a0a6992 100644 --- a/share/qtcreator/debugger/stdtypes.py +++ b/share/qtcreator/debugger/stdtypes.py @@ -659,6 +659,17 @@ def qdump__std____1__unique_ptr(d, value): qdump__std__unique_ptr(d, value) +def qdump__std__pair(d, value): + typeCode = '{%s}@{%s}' % (value.type[0].name, value.type[1].name) + first, pad, second = value.split(typeCode) + with Children(d): + key = d.putSubItem('first', first) + value = d.putSubItem('second', second) + d.putField('key', key.value) + if key.encoding is not None: + d.putField('keyencoded', key.encoding) + d.putValue(value.value, value.encoding) + def qform__std__unordered_map(): return mapForms()