diff --git a/qbs/imports/QtcProduct.qbs b/qbs/imports/QtcProduct.qbs index 0dc1e9b3b1f..1caf073e988 100644 --- a/qbs/imports/QtcProduct.qbs +++ b/qbs/imports/QtcProduct.qbs @@ -19,7 +19,14 @@ Product { Depends { name: "cpp" } Depends { name: "qtc" } - Depends { name: product.name + " dev headers"; required: false } + Depends { + name: product.name + " dev headers"; + required: false + Properties { + condition: Utilities.versionCompare(qbs.version, "1.13") >= 0 + enableFallback: false + } + } Depends { name: "Qt.core"; versionAtLeast: "5.9.0" } // TODO: Should fall back to what came from Qt.core for Qt < 5.7, but we cannot express that diff --git a/src/libs/utils/filenamevalidatinglineedit.cpp b/src/libs/utils/filenamevalidatinglineedit.cpp index 344ab99cc3a..271f325a219 100644 --- a/src/libs/utils/filenamevalidatinglineedit.cpp +++ b/src/libs/utils/filenamevalidatinglineedit.cpp @@ -97,7 +97,7 @@ void FileNameValidatingLineEdit::setForceFirstCapitalLetter(bool b) #define SLASHES "/\\" -static const char notAllowedCharsSubDir[] = ",^@=+{}[]~!?:&*\"|#%<>$\"'();`' "; +static const char notAllowedCharsSubDir[] = ",^@={}[]~!?:&*\"|#%<>$\"'();`' "; static const char notAllowedCharsNoSubDir[] = ",^@={}[]~!?:&*\"|#%<>$\"'();`' " SLASHES; static const char *notAllowedSubStrings[] = {".."}; diff --git a/src/plugins/android/androidrunnerworker.cpp b/src/plugins/android/androidrunnerworker.cpp index 0b4021e9511..6497f50d627 100644 --- a/src/plugins/android/androidrunnerworker.cpp +++ b/src/plugins/android/androidrunnerworker.cpp @@ -53,6 +53,7 @@ namespace { Q_LOGGING_CATEGORY(androidRunWorkerLog, "qtc.android.run.androidrunnerworker", QtWarningMsg) +static const int GdbTempFileMaxCounter = 20; } using namespace std; @@ -248,19 +249,60 @@ bool AndroidRunnerWorker::runAdb(const QStringList &args, QString *stdOut, return result.success(); } -bool AndroidRunnerWorker::uploadFile(const QString &from, const QString &to, const QString &flags) +bool AndroidRunnerWorker::uploadGdbServer() { - QFile f(from); - if (!f.open(QIODevice::ReadOnly)) + // Push the gdbserver to temp location and then to package dir. + // the files can't be pushed directly to package because of permissions. + qCDebug(androidRunWorkerLog) << "Uploading GdbServer"; + + bool foundUnique = true; + auto cleanUp = [this, &foundUnique] (QString *p) { + if (foundUnique && !runAdb({"shell", "rm", "-f", *p})) + qCDebug(androidRunWorkerLog) << "Gdbserver cleanup failed."; + delete p; + }; + std::unique_ptr + tempGdbServerPath(new QString("/data/local/tmp/%1"), cleanUp); + + // Get a unique temp file name for gdbserver copy + int count = 0; + while (deviceFileExists(tempGdbServerPath->arg(++count))) { + if (count > GdbTempFileMaxCounter) { + qCDebug(androidRunWorkerLog) << "Can not get temporary file name"; + foundUnique = false; + return false; + } + } + *tempGdbServerPath = tempGdbServerPath->arg(count); + + // Copy gdbserver to temp location + if (!runAdb({"push", m_gdbserverPath , *tempGdbServerPath})) { + qCDebug(androidRunWorkerLog) << "Gdbserver upload to temp directory failed"; return false; - runAdb({"shell", "run-as", m_packageName, "rm", to}); - const QByteArray data = f.readAll(); + } + + // Copy gdbserver from temp location to app directory + if (!runAdb({"shell", "run-as", m_packageName, "cp" , *tempGdbServerPath, "./gdbserver"})) { + qCDebug(androidRunWorkerLog) << "Gdbserver copy from temp directory failed"; + return false; + } + QTC_ASSERT(runAdb({"shell", "run-as", m_packageName, "chmod", "+x", "./gdbserver"}), + qCDebug(androidRunWorkerLog) << "Gdbserver chmod +x failed."); + return true; +} + +bool AndroidRunnerWorker::deviceFileExists(const QString &filePath) +{ QString output; - const bool res = runAdb({"shell", "run-as", m_packageName, QString("sh -c 'base64 -d > %1'").arg(to)}, - &output, data.toBase64()); - if (!res || output.contains("base64: not found")) - return false; - return runAdb({"shell", "run-as", m_packageName, "chmod", flags, to}); + const bool success = runAdb({"shell", "ls", filePath, "2>/dev/null"}, &output); + return success && !output.trimmed().isEmpty(); +} + +bool AndroidRunnerWorker::packageFileExists(const QString &filePath) +{ + QString output; + const bool success = runAdb({"shell", "run-as", m_packageName, "ls", filePath, "2>/dev/null"}, &output); + return success && !output.trimmed().isEmpty(); } void AndroidRunnerWorker::adbKill(qint64 pid) @@ -403,26 +445,28 @@ void AndroidRunnerWorker::asyncStartHelper() // e.g. on Android 8 with NDK 10e runAdb({"shell", "run-as", m_packageName, "chmod", "a+x", packageDir.trimmed()}); - QString gdbServerExecutable; + QString gdbServerExecutable = "gdbserver"; QString gdbServerPrefix = "./lib/"; - if (m_gdbserverPath.isEmpty() || !uploadFile(m_gdbserverPath, "gdbserver")) { - // upload failed - check for old devices - QString output; - if (runAdb({"shell", "run-as", m_packageName, "ls", "lib/"}, &output)) { - for (const auto &line: output.split('\n')) { - if (line.indexOf("gdbserver") != -1/* || line.indexOf("lldb-server") != -1*/) { - gdbServerExecutable = line.trimmed(); - break; - } - } - } - if (gdbServerExecutable.isEmpty()) { + auto findGdbServer = [this, &gdbServerExecutable, gdbServerPrefix](const QString& gdbEx) { + if (!packageFileExists(gdbServerPrefix + gdbEx)) + return false; + gdbServerExecutable = gdbEx; + return true; + }; + + if (!findGdbServer("gdbserver") && !findGdbServer("libgdbserver.so")) { + // Armv8. symlink lib is not available. + // Kill the previous instances of gdbserver. Do this before copying the gdbserver. + runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable}); + if (!m_gdbserverPath.isEmpty() && uploadGdbServer()) { + gdbServerPrefix = "./"; + } else { emit remoteProcessFinished(tr("Cannot find/copy C++ debug server.")); return; } } else { - gdbServerPrefix = "./"; - gdbServerExecutable = "gdbserver"; + qCDebug(androidRunWorkerLog) << "Found GDB server under ./lib"; + runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable}); } QString debuggerServerErr; @@ -484,7 +528,6 @@ bool AndroidRunnerWorker::startDebuggerServer(const QString &packageDir, QString *errorStr) { QString gdbServerSocket = packageDir + "/debug-socket"; - runAdb({"shell", "run-as", m_packageName, "killall", gdbServerExecutable}); runAdb({"shell", "run-as", m_packageName, "rm", gdbServerSocket}); QString gdbProcessErr; diff --git a/src/plugins/android/androidrunnerworker.h b/src/plugins/android/androidrunnerworker.h index 5e5e51cd752..30da68fc2df 100644 --- a/src/plugins/android/androidrunnerworker.h +++ b/src/plugins/android/androidrunnerworker.h @@ -47,7 +47,6 @@ public: AndroidRunnerWorker(ProjectExplorer::RunWorker *runner, const QString &packageName); ~AndroidRunnerWorker() override; - bool uploadFile(const QString &from, const QString &to, const QString &flags = QString("+x")); bool runAdb(const QStringList &args, QString *stdOut = nullptr, const QByteArray &writeData = {}); void adbKill(qint64 pid); QStringList selector() const; @@ -71,10 +70,13 @@ signals: void remoteOutput(const QString &output); void remoteErrorOutput(const QString &output); -protected: +private: void asyncStartHelper(); bool startDebuggerServer(const QString &packageDir, const QString &gdbServerPrefix, const QString &gdbServerExecutable, QString *errorStr = nullptr); + bool deviceFileExists(const QString &filePath); + bool packageFileExists(const QString& filePath); + bool uploadGdbServer(); enum class JDBState { Idle, diff --git a/src/plugins/autotest/testresultmodel.cpp b/src/plugins/autotest/testresultmodel.cpp index c1d86342f00..6cabd39cbcf 100644 --- a/src/plugins/autotest/testresultmodel.cpp +++ b/src/plugins/autotest/testresultmodel.cpp @@ -145,7 +145,7 @@ void TestResultItem::updateResult(bool &changed, Result::Type addedChildType) ? Result::MessageTestCaseSuccess : old; break; default: - return; + break; } changed = old != newResult; if (changed) diff --git a/src/plugins/coreplugin/helpitem.cpp b/src/plugins/coreplugin/helpitem.cpp index a4181b8beb9..ec5ead12e07 100644 --- a/src/plugins/coreplugin/helpitem.cpp +++ b/src/plugins/coreplugin/helpitem.cpp @@ -51,16 +51,6 @@ HelpItem::HelpItem(const QUrl &url, const QString &docMark, HelpItem::Category c , m_category(category) {} -HelpItem::HelpItem(const QUrl &url, - const QString &docMark, - HelpItem::Category category, - const QMap &helpLinks) - : m_helpUrl(url) - , m_docMark(docMark) - , m_category(category) - , m_helpLinks(helpLinks) -{} - HelpItem::HelpItem(const QString &helpId, const QString &docMark, Category category) : HelpItem(QStringList(helpId), docMark, category) {} @@ -105,6 +95,11 @@ void HelpItem::setCategory(Category cat) HelpItem::Category HelpItem::category() const { return m_category; } +bool HelpItem::isEmpty() const +{ + return m_helpUrl.isEmpty() && m_helpIds.isEmpty(); +} + bool HelpItem::isValid() const { if (m_helpUrl.isEmpty() && m_helpIds.isEmpty()) diff --git a/src/plugins/coreplugin/helpitem.h b/src/plugins/coreplugin/helpitem.h index 9ac0fd0c353..794eaca8f31 100644 --- a/src/plugins/coreplugin/helpitem.h +++ b/src/plugins/coreplugin/helpitem.h @@ -59,8 +59,6 @@ public: HelpItem(const QStringList &helpIds, const QString &docMark, Category category); explicit HelpItem(const QUrl &url); HelpItem(const QUrl &url, const QString &docMark, Category category); - HelpItem(const QUrl &url, const QString &docMark, Category category, - const QMap &helpLinks); void setHelpUrl(const QUrl &url); const QUrl &helpUrl() const; @@ -74,6 +72,7 @@ public: void setCategory(Category cat); Category category() const; + bool isEmpty() const; bool isValid() const; QString extractContent(bool extended) const; diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index b51afe098e5..8d2af5008a7 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -1714,7 +1714,7 @@ void GdbEngine::detachDebugger() { CHECK_STATE(InferiorStopOk); QTC_CHECK(runParameters().startMode != AttachCore); - DebuggerCommand cmd("detach", ExitRequest); + DebuggerCommand cmd("detach", NativeCommand | ExitRequest); cmd.callback = [this](const DebuggerResponse &) { CHECK_STATE(InferiorStopOk); notifyInferiorExited(); diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index cfaec938e71..df16af3101c 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -652,7 +652,7 @@ void HelpPluginPrivate::requestContextHelp() ? tipHelpValue.value() : HelpItem(tipHelpValue.toString()); IContext *context = ICore::currentContextObject(); - if (!tipHelp.isValid() && context) + if (tipHelp.isEmpty() && context) context->contextHelp([this](const HelpItem &item) { showContextHelp(item); }); else showContextHelp(tipHelp); diff --git a/src/plugins/help/textbrowserhelpviewer.cpp b/src/plugins/help/textbrowserhelpviewer.cpp index e0f151c30b1..d729535fa38 100644 --- a/src/plugins/help/textbrowserhelpviewer.cpp +++ b/src/plugins/help/textbrowserhelpviewer.cpp @@ -430,7 +430,8 @@ void TextBrowserHelpWidget::mouseReleaseEvent(QMouseEvent *e) bool controlPressed = e->modifiers() & Qt::ControlModifier; const QString link = linkAt(e->pos()); - if ((controlPressed || e->button() == Qt::MidButton) && !link.isEmpty()) { + if (m_parent->isActionVisible(HelpViewer::Action::NewPage) + && (controlPressed || e->button() == Qt::MidButton) && !link.isEmpty()) { emit m_parent->newPageRequested(QUrl(link)); return; } diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index f6ebaa047f8..d401f452ac6 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -591,8 +591,9 @@ void Client::handleCodeActionResponse(const CodeActionRequest::Response &respons for (const Utils::variant &item : *list) { if (auto action = Utils::get_if(&item)) updateCodeActionRefactoringMarker(this, *action, uri); - else if (auto command = Utils::get_if(&item)) - ; // todo + else if (auto command = Utils::get_if(&item)) { + Q_UNUSED(command); // todo + } } } } diff --git a/src/plugins/qmljseditor/qmljsautocompleter.cpp b/src/plugins/qmljseditor/qmljsautocompleter.cpp index 281c80d860f..5c8dc78b68c 100644 --- a/src/plugins/qmljseditor/qmljsautocompleter.cpp +++ b/src/plugins/qmljseditor/qmljsautocompleter.cpp @@ -230,7 +230,7 @@ bool AutoCompleter::contextAllowsAutoQuotes(const QTextCursor &cursor, } // never insert ' into string literals, it adds spurious ' when writing contractions - if (textToInsert.at(0) == QLatin1Char('\'')) + if (textToInsert.at(0) == QLatin1Char('\'') && quote != '\'') return false; if (textToInsert.at(0) != quote || isCompleteStringLiteral(tokenText)) diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp index d7d4892b9a8..53b3422c80e 100644 --- a/src/plugins/qmljseditor/qmljshoverhandler.cpp +++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp @@ -185,8 +185,7 @@ bool QmlJSHoverHandler::setQmlTypeHelp(const ScopeChain &scopeChain, const Docum // Use the URL, to disambiguate different versions const HelpItem helpItem(filteredUrlMap.first(), qName.join(QLatin1Char('.')), - HelpItem::QmlComponent, - filteredUrlMap); + HelpItem::QmlComponent); setLastHelpItemIdentified(helpItem); return true; } diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 6dd9004c774..0fdb332b384 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -8020,7 +8020,7 @@ void BaseTextEditor::setContextHelp(const HelpItem &item) void TextEditorWidget::contextHelpItem(const IContext::HelpCallback &callback) { - if (!d->m_contextHelpItem.isValid() && !d->m_hoverHandlers.isEmpty()) { + if (d->m_contextHelpItem.isEmpty() && !d->m_hoverHandlers.isEmpty()) { d->m_hoverHandlers.first()->contextHelpId(this, Text::wordStartCursor(textCursor()).position(), callback); diff --git a/src/tools/sdktool/adddebuggeroperation.cpp b/src/tools/sdktool/adddebuggeroperation.cpp index 6ec0716491a..e6871cb8b65 100644 --- a/src/tools/sdktool/adddebuggeroperation.cpp +++ b/src/tools/sdktool/adddebuggeroperation.cpp @@ -173,7 +173,7 @@ bool AddDebuggerOperation::test() const QVariantMap AddDebuggerOperation::addDebugger(const QVariantMap &map, const QString &id, const QString &displayName, - const quint32 &engine, const QString &binary, + int engine, const QString &binary, const QStringList &abis, const KeyValuePairList &extra) { // Sanity check: Make sure autodetection source is not in use already: diff --git a/src/tools/sdktool/adddebuggeroperation.h b/src/tools/sdktool/adddebuggeroperation.h index 754ff7210e4..5c7731d780a 100644 --- a/src/tools/sdktool/adddebuggeroperation.h +++ b/src/tools/sdktool/adddebuggeroperation.h @@ -46,7 +46,7 @@ public: static QVariantMap addDebugger(const QVariantMap &map, const QString &id, const QString &displayName, - const quint32 &engine, const QString &binary, + int engine, const QString &binary, const QStringList &abis, const KeyValuePairList &extra); static QVariantMap initializeDebuggers(); @@ -54,7 +54,7 @@ public: private: QString m_id; QString m_displayName; - quint32 m_engine = 0; + int m_engine = 0; QString m_binary; QStringList m_abis; KeyValuePairList m_extra; diff --git a/tests/system/objects.map b/tests/system/objects.map index c5f1ac43733..b3852a89eab 100644 --- a/tests/system/objects.map +++ b/tests/system/objects.map @@ -196,6 +196,8 @@ :Send to Codepaster_CodePaster::PasteView {name='CodePaster__Internal__ViewDialog' type='CodePaster::PasteView' visible='1' windowTitle='Send to Codepaster'} :Session Manager_ProjectExplorer::Internal::SessionDialog {name='ProjectExplorer__Internal__SessionDialog' type='ProjectExplorer::Internal::SessionDialog' visible='1' windowTitle='Session Manager'} :Startup.contextHelpComboBox_QComboBox {container=':Form.Startup_QGroupBox' name='contextHelpComboBox' type='QComboBox' visible='1'} +:Take a UI Tour.Cancel_QPushButton {text='Cancel' type='QPushButton' unnamed='1' visible='1' window=':Take a UI Tour_Utils::CheckableMessageBox'} +:Take a UI Tour_Utils::CheckableMessageBox {type='Utils::CheckableMessageBox' unnamed='1' visible='1' windowTitle='Take a UI Tour'} :User Interface.languageBox_QComboBox {container=':Core__Internal__GeneralSettings.User Interface_QGroupBox' name='languageBox' type='QComboBox' visible='1'} :Widget Box_qdesigner_internal::WidgetBoxTreeWidget {container=':*Qt Creator.Widget Box_QDockWidget' type='qdesigner_internal::WidgetBoxTreeWidget' unnamed='1' visible='1'} :Working Copy_Utils::BaseValidatingLineEdit {type='Utils::FancyLineEdit' unnamed='1' visible='1' window=':New Text File_ProjectExplorer::JsonWizard'} diff --git a/tests/system/shared/project_explorer.py b/tests/system/shared/project_explorer.py index 3c7ed2535d5..60b3af9f206 100644 --- a/tests/system/shared/project_explorer.py +++ b/tests/system/shared/project_explorer.py @@ -30,7 +30,7 @@ def switchViewTo(view): waitFor("not QToolTip.isVisible()", 15000) if view < ViewConstants.FIRST_AVAILABLE or view > ViewConstants.LAST_AVAILABLE: return - tabBar = waitForObject("{type='Core::Internal::FancyTabBar' unnamed='1' visible='1' " + tabBar = waitForObject("{name='ModeSelector' type='Core::Internal::FancyTabBar' visible='1' " "window=':Qt Creator_Core::Internal::MainWindow'}") mouseMove(tabBar, 20, 20 + 52 * view) if waitFor("QToolTip.isVisible()", 10000): @@ -43,7 +43,7 @@ def switchViewTo(view): test.passes("ToolTip verified") else: test.warning("ToolTip does not match", "Expected pattern: %s\nGot: %s" % (pattern, text)) - mouseClick(waitForObject("{type='Core::Internal::FancyTabBar' unnamed='1' visible='1' " + mouseClick(waitForObject("{name='ModeSelector' type='Core::Internal::FancyTabBar' visible='1' " "window=':Qt Creator_Core::Internal::MainWindow'}"), 20, 20 + 52 * view, 0, Qt.LeftButton) def __kitIsActivated__(kit): diff --git a/tests/system/shared/qtcreator.py b/tests/system/shared/qtcreator.py index cd572a4a794..4b909c6e441 100644 --- a/tests/system/shared/qtcreator.py +++ b/tests/system/shared/qtcreator.py @@ -55,7 +55,7 @@ source("../../shared/welcome.py") source("../../shared/workarounds.py") # include this at last # additionalParameters must be a list or tuple of strings or None -def startQC(additionalParameters=None, withPreparedSettingsPath=True): +def startQC(additionalParameters=None, withPreparedSettingsPath=True, cancelTour=True): global SettingsPath appWithOptions = ['"Qt Creator"' if platform.system() == 'Darwin' else "qtcreator"] if withPreparedSettingsPath: @@ -65,7 +65,10 @@ def startQC(additionalParameters=None, withPreparedSettingsPath=True): if platform.system() in ('Microsoft', 'Windows'): # for hooking into native file dialog appWithOptions.extend(('-platform', 'windows:dialogs=none')) test.log("Starting now: %s" % ' '.join(appWithOptions)) - return startApplication(' '.join(appWithOptions)) + appContext = startApplication(' '.join(appWithOptions)) + if cancelTour: + clickButton(waitForObject(":Take a UI Tour.Cancel_QPushButton")) + return appContext; def startedWithoutPluginError(): try: diff --git a/tests/system/suite_general/tst_installed_languages/test.py b/tests/system/suite_general/tst_installed_languages/test.py index 4685ef2083d..a6e104ceb31 100644 --- a/tests/system/suite_general/tst_installed_languages/test.py +++ b/tests/system/suite_general/tst_installed_languages/test.py @@ -46,7 +46,7 @@ def main(): invokeMenuItem("File", "Exit") waitForCleanShutdown() snooze(4) # wait for complete unloading of Creator - startQC() + startQC(cancelTour=False) try: # Use Locator for menu items which wouldn't work on macOS exitCommand = testData.field(lang, "Exit")