diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..277028cbb2d --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,7 @@ +Thank you for contributing to Qt Creator! Unfortunately the GitHub Qt Creator +presence is only a git mirror. + +Please submit your patch via gerrit: +https://wiki.qt.io/Qt_Creator#Setting_up_Gerrit_to_contribute_back_to_Qt_Creator + +We are sorry for the inconvenience. diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index ab0cbacd8b1..7e7c91d6a21 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -7,7 +7,7 @@ on: - 'doc/**' env: - QT_VERSION: 6.2.3 + QT_VERSION: 6.3.0 CLANG_VERSION: 14.0.3 ELFUTILS_VERSION: 0.175 CMAKE_VERSION: 3.21.1 diff --git a/dist/changes-8.0.0.md b/dist/changes-8.0.0.md index 339a4af41c8..87bf811f3df 100644 --- a/dist/changes-8.0.0.md +++ b/dist/changes-8.0.0.md @@ -10,17 +10,26 @@ the public Git repository. For example: git clone git://code.qt.io/qt-creator/qt-creator.git git log --cherry-pick --pretty=oneline origin/7.0..v8.0.0 +Help +---- + +* Added support for mouse forward and backward buttons (QTCREATORBUG-25168) + Editing ------- * Added shortcut for adding next search match to multi-selection * Added warning when editing generated file (QTCREATORBUG-27173) +* Added option for hiding line ending information * Fixed updating of annotations (QTCREATORBUG-26812) * Fixed that whitespace was not selected on double-click (QTCREATORBUG-24607) +* Fixed `Rewrap Paragraph` when indenting with tabs (QTCREATORBUG-27602) ### C++ * Removed `libclang` based code model +* Fixed that `Generate Setter and Getter` generated non-static methods for + static pointer types (QTCREATORBUG-27547) * Clangd * Increased minimum `Clangd` version to 14 * Improved performance of `compile_commands.json` creation @@ -64,6 +73,8 @@ Editing * Fixed semantic highlighting after server reset * Fixed that semantic update was delayed by `Document update threshold` even after saving +* Fixed that tooltips could appear while Qt Creator is not in the foreground +* Fixed synchronization of outline view (QTCREATORBUG-27595) ### Image Viewer @@ -73,11 +84,14 @@ Projects -------- * Added locator filter for starting run configurations +* Added `BuildSystem:Name` variable for default build directory + (QTCREATORBUG-26147) ### CMake * Added `Profile` build configuration type that is `RelWithDebInfo` with `QML debugging and profiling` +* Added `install` command to wizard generated projects * Turned `QML debugging and profiling` option on by default for `Debug` configurations * Removed hardcoded `QT_QML_DEBUG` from wizard created project files @@ -96,6 +110,7 @@ Analyzer ### Coco * Added experimental `Coco` integration +* Added visualization of code coverage in code editor ### CppCheck @@ -129,6 +144,11 @@ Platforms * Added auto-detection for MSVC ARM toolchain and debugger * Fixed ABI detection on ARM Windows +### macOS + +* Fixed import of existing builds of CMake projects that were done on the + command line (QTCREATORBUG-27591) + ### Android * Added option to connect physical device over WiFi @@ -160,6 +180,7 @@ Aaron Barany Adam Treat Alesandro Portale Alessandro Portale +Alexander Akulich Alexander Drozdov Alexandru Croitor Andre Hartmann @@ -176,6 +197,7 @@ David Schulz Dmitry Shachnev Eike Ziller Erik Verbruggen +Evgeny Shtanov Fawzi Mohamed Henning Gruendl Ihor Ivlev diff --git a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc index be900ea655c..0934b94e3d7 100644 --- a/doc/qtcreator/src/debugger/qtquick-debugging.qdoc +++ b/doc/qtcreator/src/debugger/qtquick-debugging.qdoc @@ -162,6 +162,8 @@ the application from running until the debug client connects to the server. This enables debugging from the start. + \note Setting breakpoints is only possible if the application is started with block mode. + \li Select \uicontrol Debug > \uicontrol {Start Debugging} > \uicontrol {Attach to QML Port}. diff --git a/share/qtcreator/debugger/qttypes.py b/share/qtcreator/debugger/qttypes.py index 0cacac30c25..fee0e12049a 100644 --- a/share/qtcreator/debugger/qttypes.py +++ b/share/qtcreator/debugger/qttypes.py @@ -1740,6 +1740,11 @@ def qdump__QString(d, value): d.putArrayData(data, size, d.createType('@QChar')) +def qdump__QSettingsKey(d, value): + qdump__QString(d, value) + d.putBetterType(value.type) + + def qdump__QStaticStringData(d, value): size = value.type[0] (ref, size, alloc, pad, offset, data) = value.split('iii@p%ss' % (2 * size)) diff --git a/share/qtcreator/templates/wizards/autotest/files/tst_qml.tmpl b/share/qtcreator/templates/wizards/autotest/files/tst_qml.tmpl index 5d3da10b700..e87c3dee134 100644 --- a/share/qtcreator/templates/wizards/autotest/files/tst_qml.tmpl +++ b/share/qtcreator/templates/wizards/autotest/files/tst_qml.tmpl @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick 2.15 import QtTest 1.0 TestCase { diff --git a/share/qtcreator/templates/wizards/files/qtquick2/file.qml.tpl b/share/qtcreator/templates/wizards/files/qtquick2/file.qml.tpl index 9c36e13c5bf..53df26f056d 100644 --- a/share/qtcreator/templates/wizards/files/qtquick2/file.qml.tpl +++ b/share/qtcreator/templates/wizards/files/qtquick2/file.qml.tpl @@ -1,4 +1,4 @@ -import QtQuick 2.0 +import QtQuick %{QtQuickVersion} Item { diff --git a/share/qtcreator/templates/wizards/files/qtquick2/wizard.json b/share/qtcreator/templates/wizards/files/qtquick2/wizard.json index 0fa070cf934..bcb8ca994fe 100644 --- a/share/qtcreator/templates/wizards/files/qtquick2/wizard.json +++ b/share/qtcreator/templates/wizards/files/qtquick2/wizard.json @@ -3,13 +3,16 @@ "supportedProjectTypes": [ ], "id": "Q.Qml.2", "category": "R.Qt", - "trDescription": "Creates a QML file with boilerplate code, starting with \"import QtQuick 2.0\".", + "trDescription": "Creates a QML file with boilerplate code, starting with \"import QtQuick\".", "trDisplayName": "QML File (Qt Quick 2)", "trDisplayCategory": "Qt", "iconText": "qml", "enabled": "%{JS: value('Plugins').indexOf('QmlJSEditor') >= 0}", - "options": { "key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-qml')}" }, + "options": [ + {"key": "DefaultSuffix", "value": "%{JS: Util.preferredSuffix('text/x-qml')}"}, + {"key": "QtQuickVersion", "value": "%{JS: Util.qtQuickVersion(value('TargetPath'))}"} + ], "pages" : [ diff --git a/share/qtcreator/templates/wizards/projects/consoleapp/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/consoleapp/CMakeLists.txt index b27ac6d8cab..1af66d937b6 100644 --- a/share/qtcreator/templates/wizards/projects/consoleapp/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/consoleapp/CMakeLists.txt @@ -36,3 +36,5 @@ else() qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) endif() @endif + +install(TARGETS %{ProjectName}) diff --git a/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt index 5af2f09fb67..d33adb59eb8 100644 --- a/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/plainc/CMakeLists.txt @@ -3,3 +3,5 @@ cmake_minimum_required(VERSION 3.5) project(%{ProjectName} LANGUAGES C) add_executable(%{ProjectName} %{CFileName}) + +install(TARGETS %{ProjectName}) diff --git a/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt index 214e8979d4a..c8a95f5a4ce 100644 --- a/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/plaincpp/CMakeLists.txt @@ -6,3 +6,5 @@ set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) add_executable(%{ProjectName} %{CppFileName}) + +install(TARGETS %{ProjectName}) diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.6.x.txt b/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.6.x.txt index d47f49ab3bd..03f9091f768 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.6.x.txt +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.6.x.txt @@ -27,3 +27,5 @@ set_target_properties(%{TargetName} PROPERTIES target_link_libraries(%{TargetName} PRIVATE Qt6::Quick) + +install(TARGETS %{TargetName} BUNDLE DESTINATION .) diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt index cac41d7c1e7..79ad6ad2991 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/CMakeLists.txt @@ -71,6 +71,8 @@ set_target_properties(%{ProjectName} PROPERTIES WIN32_EXECUTABLE TRUE ) +install(TARGETS %{ProjectName} BUNDLE DESTINATION .) + if(QT_VERSION_MAJOR EQUAL 6) qt_import_qml_plugins(%{ProjectName}) qt_finalize_executable(%{ProjectName}) diff --git a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt index 32ceeffc55b..9dc83c698c0 100644 --- a/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt +++ b/share/qtcreator/templates/wizards/projects/qtwidgetsapplication/CMakeLists.txt @@ -74,6 +74,8 @@ set_target_properties(%{ProjectName} PROPERTIES WIN32_EXECUTABLE TRUE ) +install(TARGETS %{ProjectName} BUNDLE DESTINATION .) + if(QT_VERSION_MAJOR EQUAL 6) qt_finalize_executable(%{ProjectName}) endif() diff --git a/src/libs/cplusplus/CppDocument.cpp b/src/libs/cplusplus/CppDocument.cpp index 60144b23204..90660f2b554 100644 --- a/src/libs/cplusplus/CppDocument.cpp +++ b/src/libs/cplusplus/CppDocument.cpp @@ -96,86 +96,6 @@ protected: } }; -class ContainingFunctionAt: protected SymbolVisitor -{ - TranslationUnit *translationUnit; - Symbol *root; - int line; - int column; - Symbol *functionSymbol; - bool foundFunction; - bool foundBlock; - - bool scopeContains(Scope* scope, int line, int column){ - if (!scope) - return false; - - int scopeStartLine{-1}, scopeStartColumn{-1}, scopeEndLine{-1}, scopeEndColumn{-1}; - translationUnit->getPosition(scope->startOffset(), &scopeStartLine, &scopeStartColumn); - translationUnit->getPosition(scope->endOffset(), &scopeEndLine, &scopeEndColumn); - - if (line < scopeStartLine || line > scopeEndLine) - return false; - - if (line > scopeStartLine && line < scopeEndLine) - return true; - - if (scopeStartLine == line && column >= scopeStartColumn) - return true; - - if (scopeEndLine == line && column <= scopeEndColumn) - return true; - - return false; - } - -public: - ContainingFunctionAt(TranslationUnit *unit, Symbol *root) - : translationUnit(unit), root(root), line(0), column(0), functionSymbol(nullptr) - , foundFunction(false), foundBlock(false) {} - - Symbol *operator()(int line, int column) - { - this->line = line; - this->column = column; - this->functionSymbol = nullptr; - accept(root); - - return foundBlock ? functionSymbol : nullptr; - } - -protected: - bool preVisit(Symbol *s) final - { - if (foundBlock) - return false; - - if (foundFunction) { - auto block = s->asBlock(); - if (!block) - return true; - - if (scopeContains(block->asScope(), line, column)) { - foundBlock = true; - return false; - } - return true; - } - - auto asFunction = s->asFunction(); - if (asFunction) { - if (s->line() < line || (s->line() == line && s->column() <= column)) { - foundFunction = scopeContains(s->asScope(), line, column); - if (foundFunction) - functionSymbol = asFunction; - } - } - - return true; - } -}; - - class FindScopeAt: protected SymbolVisitor { TranslationUnit *_unit; @@ -592,11 +512,19 @@ QString Document::functionAt(int line, int column, int *lineOpeningDeclaratorPar if (line < 1 || column < 1) return QString(); - Symbol *symbol = ContainingFunctionAt{translationUnit(), globalNamespace()}(line, column); + Symbol *symbol = lastVisibleSymbolAt(line, column); if (!symbol) return QString(); + // Find the enclosing function scope (which might be several levels up, or we might be standing + // on it) Scope *scope = symbol->asScope(); + if (!scope) + scope = symbol->enclosingScope(); + + while (scope && !scope->isFunction() ) + scope = scope->enclosingScope(); + if (!scope) return QString(); diff --git a/src/libs/cplusplus/FindUsages.cpp b/src/libs/cplusplus/FindUsages.cpp index df3f6f89f95..c82bbbf1fca 100644 --- a/src/libs/cplusplus/FindUsages.cpp +++ b/src/libs/cplusplus/FindUsages.cpp @@ -142,11 +142,30 @@ void FindUsages::reportResult(unsigned tokenIndex, const QList &cand const int len = tk.utf16chars(); const Usage u(Utils::FilePath::fromString(_doc->fileName()), lineText, - getType(line, col, tokenIndex), line, col - 1, len); + getContainingFunction(line, col), getType(line, col, tokenIndex), + line, col - 1, len); _usages.append(u); _references.append(tokenIndex); } +QString FindUsages::getContainingFunction(int line, int column) +{ + const QList astPath = ASTPath(_doc)(line, column); + bool hasBlock = false; + for (auto it = astPath.crbegin(); it != astPath.crend(); ++it) { + if (!hasBlock && (*it)->asCompoundStatement()) + hasBlock = true; + if (const auto func = (*it)->asFunctionDefinition()) { + if (!hasBlock) + return {}; + if (!func->symbol) + return {}; + return Overview().prettyName(func->symbol->name()); + } + } + return {}; +} + class FindUsages::GetUsageType { public: diff --git a/src/libs/cplusplus/FindUsages.h b/src/libs/cplusplus/FindUsages.h index 87d1cbaef52..1210a745dae 100644 --- a/src/libs/cplusplus/FindUsages.h +++ b/src/libs/cplusplus/FindUsages.h @@ -42,11 +42,14 @@ public: enum class Type { Declaration, Initialization, Read, Write, WritableRef, Other }; Usage() = default; - Usage(const Utils::FilePath &path, const QString &lineText, Type t, int line, int col, int len) - : path(path), lineText(lineText), type(t), line(line), col(col), len(len) {} + Usage(const Utils::FilePath &path, const QString &lineText, const QString &func, Type t, + int line, int col, int len) + : path(path), lineText(lineText), containingFunction(func), type(t), + line(line), col(col), len(len) {} Utils::FilePath path; QString lineText; + QString containingFunction; Type type = Type::Other; int line = 0; int col = 0; @@ -75,6 +78,7 @@ protected: void reportResult(unsigned tokenIndex, const Name *name, Scope *scope = nullptr); void reportResult(unsigned tokenIndex, const QList &candidates); Usage::Type getType(int line, int column, int tokenIndex); + QString getContainingFunction(int line, int column); bool checkCandidates(const QList &candidates) const; void checkExpression(unsigned startToken, unsigned endToken, Scope *scope = nullptr); diff --git a/src/libs/modelinglib/qmt/diagram_controller/diagramcontroller.cpp b/src/libs/modelinglib/qmt/diagram_controller/diagramcontroller.cpp index f7d7e702e5b..72eef3ef742 100644 --- a/src/libs/modelinglib/qmt/diagram_controller/diagramcontroller.cpp +++ b/src/libs/modelinglib/qmt/diagram_controller/diagramcontroller.cpp @@ -557,9 +557,11 @@ void DiagramController::onBeginResetModel() void DiagramController::onEndResetModel() { updateAllDiagramsList(); - foreach (MDiagram *diagram, m_allDiagrams) { + for (MDiagram *diagram : qAsConst(m_allDiagrams)) { + const QList elements = diagram->diagramElements(); // remove all elements which are not longer part of the model - foreach (DElement *element, diagram->diagramElements()) { + for (int i = elements.size() - 1; i >= 0; --i) { + DElement *element = elements.at(i); if (element->modelUid().isValid()) { MElement *modelElement = m_modelController->findElement(element->modelUid()); if (!modelElement) @@ -567,7 +569,7 @@ void DiagramController::onEndResetModel() } } // update all remaining elements from model - foreach (DElement *element, diagram->diagramElements()) + for (DElement *element : diagram->diagramElements()) updateElementFromModel(element, diagram, false); } emit endResetAllDiagrams(); diff --git a/src/libs/qlitehtml b/src/libs/qlitehtml index 6bfa7a2beaf..076f57c9436 160000 --- a/src/libs/qlitehtml +++ b/src/libs/qlitehtml @@ -1 +1 @@ -Subproject commit 6bfa7a2beafa897406d99e1d082b05754117a9a3 +Subproject commit 076f57c9436b55921a6477bc81660c5564c117a9 diff --git a/src/libs/utils/algorithm.h b/src/libs/utils/algorithm.h index ae4a718c836..32ad6d3e46f 100644 --- a/src/libs/utils/algorithm.h +++ b/src/libs/utils/algorithm.h @@ -76,6 +76,8 @@ bool allOf(const T &container, F predicate); ///////////////////////// template void erase(T &container, F predicate); +template +bool eraseOne(T &container, F predicate); ///////////////////////// // contains @@ -442,7 +444,15 @@ void erase(T &container, F predicate) container.erase(std::remove_if(std::begin(container), std::end(container), predicate), std::end(container)); } - +template +bool eraseOne(T &container, F predicate) +{ + const auto it = std::find_if(std::begin(container), std::end(container), predicate); + if (it == std::end(container)) + return false; + container.erase(it); + return true; +} ////////////////// // contains diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 1d469ec2ef4..14436bdc1d1 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -527,10 +527,11 @@ QString FilePath::fileNameWithPathComponents(int pathComponents) const ; } - // If there are no more slashes before the found one, return the entire string if (i > 0 && m_data.lastIndexOf(slash, i) != -1) return m_data.mid(component); - return m_data; + + // If there are no more slashes before the found one, return the entire string + return displayName(); } /// \returns the base name of the file without the path. diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index fc8ea36042f..c3d2b8942ab 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -89,21 +89,6 @@ CallerHandle::~CallerHandle() qDeleteAll(m_signals); } -bool CallerHandle::waitForStarted(int msecs) -{ - return waitForSignal(msecs, SignalType::Started); -} - -bool CallerHandle::waitForReadyRead(int msces) -{ - return waitForSignal(msces, SignalType::ReadyRead); -} - -bool CallerHandle::waitForFinished(int msecs) -{ - return waitForSignal(msecs, SignalType::Done); -} - void CallerHandle::flush() { flushFor(SignalType::NoSignal); @@ -329,11 +314,11 @@ void CallerHandle::setProcessSetupData(ProcessSetupData *setup) m_setup = setup; } -bool CallerHandle::waitForSignal(int msecs, SignalType newSignal) +bool CallerHandle::waitForSignal(SignalType signalType, int msecs) { QTC_ASSERT(isCalledFromCallersThread(), return false); QTC_ASSERT(m_launcherHandle, return false); - return m_launcherHandle->waitForSignal(msecs, newSignal); + return m_launcherHandle->waitForSignal(signalType, msecs); } // Called from caller's or launcher's thread. @@ -351,7 +336,7 @@ bool CallerHandle::isCalledFromLaunchersThread() const } // Called from caller's thread exclusively. -bool LauncherHandle::waitForSignal(int msecs, CallerHandle::SignalType newSignal) +bool LauncherHandle::waitForSignal(CallerHandle::SignalType newSignal, int msecs) { QTC_ASSERT(!isCalledFromLaunchersThread(), return false); QDeadlineTimer deadline(msecs); diff --git a/src/libs/utils/launchersocket.h b/src/libs/utils/launchersocket.h index 081cd314659..4956bf652bf 100644 --- a/src/libs/utils/launchersocket.h +++ b/src/libs/utils/launchersocket.h @@ -73,9 +73,7 @@ public: LauncherHandle *launcherHandle() const { return m_launcherHandle; } void setLauncherHandle(LauncherHandle *handle) { QMutexLocker locker(&m_mutex); m_launcherHandle = handle; } - bool waitForStarted(int msecs); - bool waitForReadyRead(int msces); - bool waitForFinished(int msecs); + bool waitForSignal(CallerHandle::SignalType signalType, int msecs); // Returns the list of flushed signals. void flush(); @@ -109,8 +107,6 @@ signals: void done(const Utils::ProcessResultData &resultData); private: - bool waitForSignal(int msecs, SignalType newSignal); - // Called from caller's thread exclusively. void sendPacket(const Internal::LauncherPacket &packet); // Called from caller's or launcher's thread. @@ -158,7 +154,7 @@ public: // Called from caller's thread, moved to launcher's thread afterwards. LauncherHandle(quintptr token) : m_token(token) {} // Called from caller's thread exclusively. - bool waitForSignal(int msecs, CallerHandle::SignalType newSignal); + bool waitForSignal(CallerHandle::SignalType newSignal, int msecs); CallerHandle *callerHandle() const { return m_callerHandle; } void setCallerHandle(CallerHandle *handle) { QMutexLocker locker(&m_mutex); m_callerHandle = handle; } diff --git a/src/libs/utils/mimetypes2/mimeutils.cpp b/src/libs/utils/mimetypes2/mimeutils.cpp index ffa2488df19..676398bb140 100644 --- a/src/libs/utils/mimetypes2/mimeutils.cpp +++ b/src/libs/utils/mimetypes2/mimeutils.cpp @@ -60,12 +60,6 @@ MimeType mimeTypeForFile(const QString &fileName, MimeMatchMode mode) return mdb.mimeTypeForFile(fileName, MimeDatabase::MatchMode(mode)); } -MimeType mimeTypeForFile(const QFileInfo &fileInfo, MimeMatchMode mode) -{ - MimeDatabase mdb; - return mdb.mimeTypeForFile(fileInfo, MimeDatabase::MatchMode(mode)); -} - MimeType mimeTypeForFile(const FilePath &filePath, MimeMatchMode mode) { MimeDatabase mdb; diff --git a/src/libs/utils/mimeutils.h b/src/libs/utils/mimeutils.h index e334258c732..7b3071ff609 100644 --- a/src/libs/utils/mimeutils.h +++ b/src/libs/utils/mimeutils.h @@ -44,10 +44,6 @@ #include #include -QT_BEGIN_NAMESPACE -class QFileInfo; -QT_END_NAMESPACE - namespace Utils { class FilePath; @@ -59,8 +55,6 @@ enum class MimeMatchMode { MatchDefault = 0x0, MatchExtension = 0x1, MatchConten QTCREATOR_UTILS_EXPORT MimeType mimeTypeForFile(const QString &fileName, MimeMatchMode mode = MimeMatchMode::MatchDefault); -QTCREATOR_UTILS_EXPORT MimeType mimeTypeForFile(const QFileInfo &fileInfo, - MimeMatchMode mode = MimeMatchMode::MatchDefault); QTCREATOR_UTILS_EXPORT MimeType mimeTypeForFile(const FilePath &filePath, MimeMatchMode mode = MimeMatchMode::MatchDefault); QTCREATOR_UTILS_EXPORT QList mimeTypesForFileName(const QString &fileName); diff --git a/src/libs/utils/processinterface.h b/src/libs/utils/processinterface.h index 727d3caf946..0ca1cc1f15d 100644 --- a/src/libs/utils/processinterface.h +++ b/src/libs/utils/processinterface.h @@ -85,13 +85,22 @@ enum class ProcessSignalType { Done }; +class QTCREATOR_UTILS_EXPORT ProcessBlockingInterface : public QObject +{ +private: + // Wait for: + // - Started is being called only in Starting state. + // - ReadyRead is being called in Starting or Running state. + // - Done is being called in Starting or Running state. + virtual bool waitForSignal(ProcessSignalType signalType, int msecs) = 0; + + friend class Internal::QtcProcessPrivate; +}; + class QTCREATOR_UTILS_EXPORT ProcessInterface : public QObject { Q_OBJECT -public: - ProcessInterface(QObject *parent = nullptr) : QObject(parent) {} - signals: // This should be emitted when being in Starting state only. // After emitting this signal the process enters Running state. @@ -121,14 +130,7 @@ private: // It's being called in Starting or Running state. virtual void sendControlSignal(ControlSignal controlSignal) = 0; - // It's being called only in Starting state. - virtual bool waitForStarted(int msecs) = 0; - - // It's being called in Starting or Running state. - virtual bool waitForReadyRead(int msecs) = 0; - - // It's being called in Starting or Running state. - virtual bool waitForFinished(int msecs) = 0; + virtual ProcessBlockingInterface *processBlockingInterface() const { return nullptr; } friend class QtcProcess; friend class Internal::QtcProcessPrivate; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index b309106f6be..925038086f4 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -322,10 +322,34 @@ bool DefaultImpl::ensureProgramExists(const QString &program) return false; } +class QProcessBlockingImpl : public ProcessBlockingInterface +{ +public: + QProcessBlockingImpl(QProcess *process) : m_process(process) {} + +private: + bool waitForSignal(ProcessSignalType signalType, int msecs) final + { + switch (signalType) { + case ProcessSignalType::Started: + return m_process->waitForStarted(msecs); + case ProcessSignalType::ReadyRead: + return m_process->waitForReadyRead(msecs); + case ProcessSignalType::Done: + return m_process->waitForFinished(msecs); + } + return false; + } + + QProcess *m_process = nullptr; +}; + class QProcessImpl final : public DefaultImpl { public: - QProcessImpl() : m_process(new ProcessHelper(this)) + QProcessImpl() + : m_process(new ProcessHelper(this)) + , m_blockingImpl(new QProcessBlockingImpl(m_process)) { connect(m_process, &QProcess::started, this, &QProcessImpl::handleStarted); @@ -361,9 +385,7 @@ private: } } - bool waitForStarted(int msecs) final { return m_process->waitForStarted(msecs); } - bool waitForReadyRead(int msecs) final { return m_process->waitForReadyRead(msecs); } - bool waitForFinished(int msecs) final { return m_process->waitForFinished(msecs); } + virtual ProcessBlockingInterface *processBlockingInterface() const { return m_blockingImpl; } void doDefaultStart(const QString &program, const QStringList &arguments) final { @@ -411,7 +433,8 @@ private: emit done(result); } - ProcessHelper *m_process; + ProcessHelper *m_process = nullptr; + QProcessBlockingImpl *m_blockingImpl = nullptr; }; static uint uniqueToken() @@ -420,6 +443,33 @@ static uint uniqueToken() return ++globalUniqueToken; } +class ProcessLauncherBlockingImpl : public ProcessBlockingInterface +{ +public: + ProcessLauncherBlockingImpl(CallerHandle *caller) : m_caller(caller) {} + +private: + bool waitForSignal(ProcessSignalType signalType, int msecs) final + { + // TODO: Remove CallerHandle::SignalType + const CallerHandle::SignalType type = [signalType] { + switch (signalType) { + case ProcessSignalType::Started: + return CallerHandle::SignalType::Started; + case ProcessSignalType::ReadyRead: + return CallerHandle::SignalType::ReadyRead; + case ProcessSignalType::Done: + return CallerHandle::SignalType::Done; + } + QTC_CHECK(false); + return CallerHandle::SignalType::NoSignal; + }(); + return m_caller->waitForSignal(type, msecs); + } + + CallerHandle *m_caller = nullptr; +}; + class ProcessLauncherImpl final : public DefaultImpl { Q_OBJECT @@ -434,6 +484,7 @@ public: this, &ProcessInterface::readyRead); connect(m_handle, &CallerHandle::done, this, &ProcessInterface::done); + m_blockingImpl = new ProcessLauncherBlockingImpl(m_handle); } ~ProcessLauncherImpl() final { @@ -462,9 +513,7 @@ private: } } - bool waitForStarted(int msecs) final { return m_handle->waitForStarted(msecs); } - bool waitForReadyRead(int msecs) final { return m_handle->waitForReadyRead(msecs); } - bool waitForFinished(int msecs) final { return m_handle->waitForFinished(msecs); } + virtual ProcessBlockingInterface *processBlockingInterface() const { return m_blockingImpl; } void doDefaultStart(const QString &program, const QStringList &arguments) final { @@ -476,6 +525,7 @@ private: const uint m_token = 0; // Lives in caller's thread. CallerHandle *m_handle = nullptr; + ProcessLauncherBlockingImpl *m_blockingImpl = nullptr; }; static ProcessImpl defaultProcessImpl() @@ -535,13 +585,15 @@ private: const ProcessResultData m_resultData; }; +class GeneralProcessBlockingImpl; + class ProcessInterfaceHandler : public QObject { public: - ProcessInterfaceHandler(QtcProcessPrivate *caller, ProcessInterface *process); + ProcessInterfaceHandler(GeneralProcessBlockingImpl *caller, ProcessInterface *process); // Called from caller's thread exclusively. - bool waitForSignal(int msecs, ProcessSignalType newSignal); + bool waitForSignal(ProcessSignalType newSignal, int msecs); void moveToCallerThread(); private: @@ -555,11 +607,44 @@ private: void handleDone(const ProcessResultData &data); void appendSignal(ProcessInterfaceSignal *newSignal); - QtcProcessPrivate *m_caller = nullptr; + GeneralProcessBlockingImpl *m_caller = nullptr; QMutex m_mutex; QWaitCondition m_waitCondition; }; +class GeneralProcessBlockingImpl : public ProcessBlockingInterface +{ +public: + GeneralProcessBlockingImpl(QtcProcessPrivate *parent); + + void flush() { flushSignals(takeAllSignals()); } + bool flushFor(ProcessSignalType signalType) { + return flushSignals(takeSignalsFor(signalType), &signalType); + } + + bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); } + // Called from ProcessInterfaceHandler thread exclusively. + void appendSignal(ProcessInterfaceSignal *launcherSignal); + +private: + // Called from caller's thread exclusively + bool waitForSignal(ProcessSignalType newSignal, int msecs) final; + + QList takeAllSignals(); + QList takeSignalsFor(ProcessSignalType signalType); + bool flushSignals(const QList &signalList, + ProcessSignalType *signalType = nullptr); + + void handleStartedSignal(const StartedSignal *launcherSignal); + void handleReadyReadSignal(const ReadyReadSignal *launcherSignal); + void handleDoneSignal(const DoneSignal *launcherSignal); + + QtcProcessPrivate *m_caller = nullptr; + std::unique_ptr m_processHandler; + mutable QMutex m_mutex; + QList m_signals; +}; + class QtcProcessPrivate : public QObject { public: @@ -591,11 +676,18 @@ public: void setProcessInterface(ProcessInterface *process) { m_process.reset(process); - m_processHandler.reset(new ProcessInterfaceHandler(this, process)); + m_process->setParent(this); + connect(m_process.get(), &ProcessInterface::started, + this, &QtcProcessPrivate::handleStarted); + connect(m_process.get(), &ProcessInterface::readyRead, + this, &QtcProcessPrivate::handleReadyRead); + connect(m_process.get(), &ProcessInterface::done, + this, &QtcProcessPrivate::handleDone); - // In order to move the process into another thread together with handle - m_process->setParent(m_processHandler.get()); - m_processHandler->setParent(this); + m_blockingInterface.reset(process->processBlockingInterface()); + if (!m_blockingInterface) + m_blockingInterface.reset(new GeneralProcessBlockingImpl(this)); + m_blockingInterface->setParent(this); } CommandLine fullCommandLine() const @@ -624,14 +716,11 @@ public: } QtcProcess *q; - std::unique_ptr m_processHandler; + std::unique_ptr m_blockingInterface; std::unique_ptr m_process; ProcessSetupData m_setup; void slotTimeout(); - void handleStartedSignal(const StartedSignal *launcherSignal); - void handleReadyReadSignal(const ReadyReadSignal *launcherSignal); - void handleDoneSignal(const DoneSignal *launcherSignal); void handleStarted(qint64 processId, qint64 applicationMainThreadId); void handleReadyRead(const QByteArray &outputData, const QByteArray &errorData); void handleDone(const ProcessResultData &data); @@ -647,31 +736,11 @@ public: ProcessResult interpretExitCode(int exitCode); - // === ProcessInterfaceHandler related === - // Called from caller's thread exclusively - bool waitForSignal(int msecs, ProcessSignalType newSignal); - void flush() { flushSignals(takeAllSignals()); } - bool flushFor(ProcessSignalType signalType) { - return flushSignals(takeSignalsFor(signalType), &signalType); - } - - QList takeAllSignals(); - QList takeSignalsFor(ProcessSignalType signalType); - bool flushSignals(const QList &signalList, - ProcessSignalType *signalType = nullptr); - - bool shouldFlush() const { QMutexLocker locker(&m_mutex); return !m_signals.isEmpty(); } + bool waitForSignal(ProcessSignalType signalType, int msecs); Qt::ConnectionType connectionType() const; void sendControlSignal(ControlSignal controlSignal); - // Called from ProcessInterfaceHandler thread exclusively. - void appendSignal(ProcessInterfaceSignal *launcherSignal); - mutable QMutex m_mutex; - QList m_signals; QTimer m_killTimer; - - // ======================================= - QProcess::ProcessState m_state = QProcess::NotRunning; qint64 m_processId = 0; qint64 m_applicationMainThreadId = 0; @@ -692,10 +761,11 @@ public: Guard m_guard; }; -ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller, +ProcessInterfaceHandler::ProcessInterfaceHandler(GeneralProcessBlockingImpl *caller, ProcessInterface *process) : m_caller(caller) { + process->disconnect(); connect(process, &ProcessInterface::started, this, &ProcessInterfaceHandler::handleStarted); connect(process, &ProcessInterface::readyRead, @@ -705,7 +775,7 @@ ProcessInterfaceHandler::ProcessInterfaceHandler(QtcProcessPrivate *caller, } // Called from caller's thread exclusively. -bool ProcessInterfaceHandler::waitForSignal(int msecs, ProcessSignalType newSignal) +bool ProcessInterfaceHandler::waitForSignal(ProcessSignalType newSignal, int msecs) { QDeadlineTimer deadline(msecs); while (true) { @@ -769,17 +839,20 @@ void ProcessInterfaceHandler::appendSignal(ProcessInterfaceSignal *newSignal) } m_waitCondition.wakeOne(); // call in callers thread - QMetaObject::invokeMethod(m_caller, &QtcProcessPrivate::flush); + QMetaObject::invokeMethod(m_caller, &GeneralProcessBlockingImpl::flush); } -// Called from caller's thread exclusively -bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal) +GeneralProcessBlockingImpl::GeneralProcessBlockingImpl(QtcProcessPrivate *parent) + : m_caller(parent) + , m_processHandler(new ProcessInterfaceHandler(this, parent->m_process.get())) { - const QDeadlineTimer timeout(msecs); - const QDeadlineTimer currentKillTimeout(m_killTimer.remainingTime()); - const bool needsSplit = m_killTimer.isActive() ? timeout > currentKillTimeout : false; - const QDeadlineTimer mainTimeout = needsSplit ? currentKillTimeout : timeout; + // In order to move the process interface into another thread together with handle + parent->m_process.get()->setParent(m_processHandler.get()); + m_processHandler->setParent(this); +} +bool GeneralProcessBlockingImpl::waitForSignal(ProcessSignalType newSignal, int msecs) +{ m_processHandler->setParent(nullptr); QThread thread; @@ -789,12 +862,7 @@ bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal) // the caller here is blocked, so all signals should be buffered and we are going // to flush them from inside waitForSignal(). m_processHandler->moveToThread(&thread); - bool result = m_processHandler->waitForSignal(mainTimeout.remainingTime(), newSignal); - if (!result && needsSplit) { - m_killTimer.stop(); - sendControlSignal(ControlSignal::Kill); - result = m_processHandler->waitForSignal(timeout.remainingTime(), newSignal); - } + const bool result = m_processHandler->waitForSignal(newSignal, msecs); m_processHandler->moveToCallerThread(); m_processHandler->setParent(this); thread.quit(); @@ -803,14 +871,14 @@ bool QtcProcessPrivate::waitForSignal(int msecs, ProcessSignalType newSignal) } // Called from caller's thread exclusively -QList QtcProcessPrivate::takeAllSignals() +QList GeneralProcessBlockingImpl::takeAllSignals() { QMutexLocker locker(&m_mutex); return std::exchange(m_signals, {}); } // Called from caller's thread exclusively -QList QtcProcessPrivate::takeSignalsFor(ProcessSignalType signalType) +QList GeneralProcessBlockingImpl::takeSignalsFor(ProcessSignalType signalType) { // If we are flushing for ReadyRead or Done - flush all. if (signalType != ProcessSignalType::Started) @@ -840,7 +908,7 @@ QList QtcProcessPrivate::takeSignalsFor(ProcessSignalT } // Called from caller's thread exclusively -bool QtcProcessPrivate::flushSignals(const QList &signalList, +bool GeneralProcessBlockingImpl::flushSignals(const QList &signalList, ProcessSignalType *signalType) { bool signalMatched = false; @@ -866,14 +934,50 @@ bool QtcProcessPrivate::flushSignals(const QList &sign return signalMatched; } -// Called from caller's thread exclusively +void GeneralProcessBlockingImpl::handleStartedSignal(const StartedSignal *aSignal) +{ + m_caller->handleStarted(aSignal->processId(), aSignal->applicationMainThreadId()); +} + +void GeneralProcessBlockingImpl::handleReadyReadSignal(const ReadyReadSignal *aSignal) +{ + m_caller->handleReadyRead(aSignal->stdOut(), aSignal->stdErr()); +} + +void GeneralProcessBlockingImpl::handleDoneSignal(const DoneSignal *aSignal) +{ + m_caller->handleDone(aSignal->resultData()); +} + +// Called from ProcessInterfaceHandler thread exclusively. +void GeneralProcessBlockingImpl::appendSignal(ProcessInterfaceSignal *newSignal) +{ + QMutexLocker locker(&m_mutex); + m_signals.append(newSignal); +} + +bool QtcProcessPrivate::waitForSignal(ProcessSignalType newSignal, int msecs) +{ + const QDeadlineTimer timeout(msecs); + const QDeadlineTimer currentKillTimeout(m_killTimer.remainingTime()); + const bool needsSplit = m_killTimer.isActive() ? timeout > currentKillTimeout : false; + const QDeadlineTimer mainTimeout = needsSplit ? currentKillTimeout : timeout; + + bool result = m_blockingInterface->waitForSignal(newSignal, mainTimeout.remainingTime()); + if (!result && needsSplit) { + m_killTimer.stop(); + sendControlSignal(ControlSignal::Kill); + result = m_blockingInterface->waitForSignal(newSignal, timeout.remainingTime()); + } + return result; +} + Qt::ConnectionType QtcProcessPrivate::connectionType() const { return (m_process->thread() == thread()) ? Qt::DirectConnection : Qt::BlockingQueuedConnection; } -// Called from caller's thread exclusively void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal) { QTC_ASSERT(QThread::currentThread() == thread(), return); @@ -885,13 +989,6 @@ void QtcProcessPrivate::sendControlSignal(ControlSignal controlSignal) }, connectionType()); } -// Called from ProcessInterfaceHandler thread exclusively. -void QtcProcessPrivate::appendSignal(ProcessInterfaceSignal *newSignal) -{ - QMutexLocker locker(&m_mutex); - m_signals.append(newSignal); -} - void QtcProcessPrivate::clearForRun() { m_hangTimerCount = 0; @@ -1188,17 +1285,6 @@ void QtcProcess::setRemoteProcessHooks(const DeviceProcessHooks &hooks) s_deviceHooks = hooks; } -void QtcProcess::stopProcess() -{ - if (state() == QProcess::NotRunning) - return; - terminate(); - if (waitForFinished(300)) - return; - kill(); - waitForFinished(300); -} - static bool askToKill(const QString &command) { #ifdef QT_GUI_LIB @@ -1275,7 +1361,7 @@ bool QtcProcess::readDataFromProcess(int timeoutS, QString QtcProcess::normalizeNewlines(const QString &text) { QString res = text; - const auto newEnd = std::unique(res.begin(), res.end(), [](const QChar &c1, const QChar &c2) { + const auto newEnd = std::unique(res.begin(), res.end(), [](const QChar c1, const QChar c2) { return c1 == '\r' && c2 == '\r'; // QTCREATORBUG-24556 }); res.chop(std::distance(newEnd, res.end())); @@ -1444,8 +1530,8 @@ bool QtcProcess::waitForStarted(int msecs) return true; if (d->m_state == QProcess::NotRunning) return false; - return s_waitForStarted.measureAndRun(&QtcProcessPrivate::waitForSignal, d, msecs, - ProcessSignalType::Started); + return s_waitForStarted.measureAndRun(&QtcProcessPrivate::waitForSignal, d, + ProcessSignalType::Started, msecs); } bool QtcProcess::waitForReadyRead(int msecs) @@ -1453,7 +1539,7 @@ bool QtcProcess::waitForReadyRead(int msecs) QTC_ASSERT(d->m_process, return false); if (d->m_state == QProcess::NotRunning) return false; - return d->waitForSignal(msecs, ProcessSignalType::ReadyRead); + return d->waitForSignal(ProcessSignalType::ReadyRead, msecs); } bool QtcProcess::waitForFinished(int msecs) @@ -1461,7 +1547,7 @@ bool QtcProcess::waitForFinished(int msecs) QTC_ASSERT(d->m_process, return false); if (d->m_state == QProcess::NotRunning) return false; - return d->waitForSignal(msecs, ProcessSignalType::Done); + return d->waitForSignal(ProcessSignalType::Done, msecs); } QByteArray QtcProcess::readAllStandardOutput() @@ -1511,9 +1597,9 @@ void QtcProcess::close() d->m_process->disconnect(); d->m_process.release()->deleteLater(); } - if (d->m_processHandler) { - d->m_processHandler->disconnect(); - d->m_processHandler.release()->deleteLater(); + if (d->m_blockingInterface) { + d->m_blockingInterface->disconnect(); + d->m_blockingInterface.release()->deleteLater(); } d->clearForRun(); } @@ -1618,10 +1704,16 @@ QString QtcProcess::allOutput() const return !out.isEmpty() ? out : err; } +QByteArray QtcProcess::rawStdOut() const +{ + QTC_CHECK(d->m_stdOut.keepRawData); + return d->m_stdOut.rawData; +} + QString QtcProcess::stdOut() const { QTC_CHECK(d->m_stdOut.keepRawData); - return normalizeNewlines(d->m_codec->toUnicode(d->m_stdOut.rawData)); + return d->m_codec->toUnicode(d->m_stdOut.rawData); } QString QtcProcess::stdErr() const @@ -1631,13 +1723,37 @@ QString QtcProcess::stdErr() const // is not trivial. So weaken it a bit for now. //QTC_CHECK(d->m_stdErr.keepRawData); QTC_CHECK(d->m_stdErr.keepRawData || d->m_stdErr.rawData.isEmpty()); - return normalizeNewlines(d->m_codec->toUnicode(d->m_stdErr.rawData)); + return d->m_codec->toUnicode(d->m_stdErr.rawData); } -QByteArray QtcProcess::rawStdOut() const +QString QtcProcess::cleanedStdOut() const { - QTC_CHECK(d->m_stdOut.keepRawData); - return d->m_stdOut.rawData; + return normalizeNewlines(stdOut()); +} + +QString QtcProcess::cleanedStdErr() const +{ + return normalizeNewlines(stdErr()); +} + +static QStringList splitLines(const QString &text) +{ + QStringList result = text.split('\n'); + for (QString &line : result) { + if (line.endsWith('\r')) + line.chop(1); + } + return result; +} + +const QStringList QtcProcess::stdOutLines() const +{ + return splitLines(stdOut()); +} + +const QStringList QtcProcess::stdErrLines() const +{ + return splitLines(stdErr()); } QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r) @@ -1843,7 +1959,8 @@ void QtcProcessPrivate::slotTimeout() || askToKill(m_setup.m_commandLine.executable().toString()); m_waitingForUser = false; if (terminate) { - q->stopProcess(); + q->stop(); + q->waitForFinished(); m_result = ProcessResult::Hang; } else { m_hangTimerCount = 0; @@ -1854,22 +1971,6 @@ void QtcProcessPrivate::slotTimeout() } } -void QtcProcessPrivate::handleStartedSignal(const StartedSignal *aSignal) -{ - handleStarted(aSignal->processId(), aSignal->applicationMainThreadId()); -} - -void QtcProcessPrivate::handleReadyReadSignal(const ReadyReadSignal *aSignal) -{ - handleReadyRead(aSignal->stdOut(), aSignal->stdErr()); -} - -void QtcProcessPrivate::handleDoneSignal(const DoneSignal *aSignal) -{ - m_killTimer.stop(); - handleDone(aSignal->resultData()); -} - void QtcProcessPrivate::handleStarted(qint64 processId, qint64 applicationMainThreadId) { QTC_CHECK(m_state == QProcess::Starting); @@ -1908,6 +2009,7 @@ void QtcProcessPrivate::handleReadyRead(const QByteArray &outputData, const QByt void QtcProcessPrivate::handleDone(const ProcessResultData &data) { + m_killTimer.stop(); m_resultData = data; switch (m_state) { diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 15cc4693c3c..42c981a3431 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -175,7 +175,6 @@ public: void setStdErrCallback(const std::function &callback); void setStdErrLineCallback(const std::function &callback); - void stopProcess(); bool readDataFromProcess(int timeoutS, QByteArray *stdOut, QByteArray *stdErr, bool showTimeOutMessageBox); @@ -185,11 +184,17 @@ public: QByteArray allRawOutput() const; QString allOutput() const; - QString stdOut() const; - QString stdErr() const; - QByteArray rawStdOut() const; + QString stdOut() const; // possibly with CR + QString stdErr() const; // possibly with CR + + QString cleanedStdOut() const; // with CR removed + QString cleanedStdErr() const; // with CR removed + + const QStringList stdOutLines() const; // split, CR removed + const QStringList stdErrLines() const; // split, CR removed + QString exitMessage() const; QString toStandaloneCommandLine() const; diff --git a/src/libs/utils/shellcommand.cpp b/src/libs/utils/shellcommand.cpp index 00f655a1ef6..6f8a49de019 100644 --- a/src/libs/utils/shellcommand.cpp +++ b/src/libs/utils/shellcommand.cpp @@ -368,7 +368,10 @@ void ShellCommand::runFullySynchronous(QtcProcess &process, const FilePath &work void ShellCommand::runSynchronous(QtcProcess &process, const FilePath &workingDirectory) { - connect(this, &ShellCommand::terminate, &process, &QtcProcess::stopProcess); + connect(this, &ShellCommand::terminate, &process, [&process] { + process.stop(); + process.waitForFinished(); + }); process.setEnvironment(processEnvironment()); if (d->m_codec) process.setCodec(d->m_codec); diff --git a/src/libs/utils/terminalprocess_p.h b/src/libs/utils/terminalprocess_p.h index f92d00f8448..32be83f0206 100644 --- a/src/libs/utils/terminalprocess_p.h +++ b/src/libs/utils/terminalprocess_p.h @@ -50,12 +50,6 @@ private: qint64 write(const QByteArray &) final { QTC_CHECK(false); return -1; } void sendControlSignal(ControlSignal controlSignal) final; - // intentionally no-op without an assert - bool waitForStarted(int) final { return false; } - bool waitForReadyRead(int) final { QTC_CHECK(false); return false; } - // intentionally no-op without an assert - bool waitForFinished(int) final { return false; } - // OK, however, impl looks a bit different (!= NotRunning vs == Running). // Most probably changing it into (== Running) should be OK. bool isRunning() const; diff --git a/src/plugins/android/androidqmlpreviewworker.cpp b/src/plugins/android/androidqmlpreviewworker.cpp index 103e7b2e5c3..b739c1de768 100644 --- a/src/plugins/android/androidqmlpreviewworker.cpp +++ b/src/plugins/android/androidqmlpreviewworker.cpp @@ -127,7 +127,7 @@ bool AndroidQmlPreviewWorker::isPreviewRunning(int lastKnownPid) const void AndroidQmlPreviewWorker::startPidWatcher() { - m_pidFutureWatcher.setFuture(Utils::runAsync([this]() { + m_pidFutureWatcher.setFuture(runAsync([this]() { // wait for started const int sleepTimeMs = 2000; QDeadlineTimer deadline(20000); @@ -157,7 +157,7 @@ void AndroidQmlPreviewWorker::startLogcat() QString args = QString("logcat --pid=%1").arg(m_viewerPid); if (!m_logcatStartTimeStamp.isEmpty()) args += QString(" -T '%1'").arg(m_logcatStartTimeStamp); - Utils::CommandLine cmd(AndroidConfigurations::currentConfig().adbToolPath()); + CommandLine cmd(AndroidConfigurations::currentConfig().adbToolPath()); cmd.setArguments(args); m_logcatProcess.setCommand(cmd); m_logcatProcess.setUseCtrlCStub(true); @@ -190,7 +190,7 @@ AndroidQmlPreviewWorker::AndroidQmlPreviewWorker(ProjectExplorer::RunControl *ru connect(this, &AndroidQmlPreviewWorker::previewPidChanged, this, &AndroidQmlPreviewWorker::startLogcat); - connect(this, &RunWorker::stopped, &m_logcatProcess, &Utils::QtcProcess::stopProcess); + connect(this, &RunWorker::stopped, &m_logcatProcess, &QtcProcess::stop); m_logcatProcess.setStdOutCallback([this](const QString &stdOut) { filterLogcatAndAppendMessage(stdOut); }); @@ -314,7 +314,7 @@ bool AndroidQmlPreviewWorker::preparePreviewArtefacts() } } else { const FilePaths allFiles = m_rc->project()->files(m_rc->project()->SourceFiles); - const FilePaths filesToExport = Utils::filtered(allFiles,[](const FilePath &path) { + const FilePaths filesToExport = filtered(allFiles, [](const FilePath &path) { return path.suffix() == "qmlproject"; }); @@ -363,7 +363,8 @@ FilePath AndroidQmlPreviewWorker::createQmlrcFile(const FilePath &workFolder, QByteArray stdOut; QByteArray stdErr; if (!rccProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) { - rccProcess.stopProcess(); + rccProcess.stop(); + rccProcess.waitForFinished(); appendMessage(tr("A timeout occurred running \"%1\""). arg(rccProcess.commandLine().toUserOutput()), StdErrFormat); qrcPath.removeFile(); diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index d238e60ef38..628f245c349 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -166,8 +166,10 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar proc.setTimeoutS(timeout); proc.setStdOutCallback([offset, progressQuota, &proc, &assertionFound, &fi](const QString &out) { int progressPercent = parseProgress(out, assertionFound); - if (assertionFound) - proc.stopProcess(); + if (assertionFound) { + proc.stop(); + proc.waitForFinished(); + } if (progressPercent != -1) fi.setProgressValue(offset + qRound((progressPercent / 100.0) * progressQuota)); }); @@ -175,8 +177,10 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar output.stdError = err; }); if (interruptible) { - QObject::connect(&sdkManager, &AndroidSdkManager::cancelActiveOperations, - &proc, &QtcProcess::stopProcess); + QObject::connect(&sdkManager, &AndroidSdkManager::cancelActiveOperations, &proc, [&proc] { + proc.stop(); + proc.waitForFinished(); + }); } proc.setCommand({config.sdkManagerToolPath(), newArgs}); proc.runBlocking(EventLoopMode::On); diff --git a/src/plugins/autotest/boost/boosttestconfiguration.cpp b/src/plugins/autotest/boost/boosttestconfiguration.cpp index 5e65962a52e..556228bd653 100644 --- a/src/plugins/autotest/boost/boosttestconfiguration.cpp +++ b/src/plugins/autotest/boost/boosttestconfiguration.cpp @@ -39,7 +39,7 @@ namespace Autotest { namespace Internal { TestOutputReader *BoostTestConfiguration::outputReader(const QFutureInterface &fi, - QProcess *app) const + Utils::QtcProcess *app) const { auto settings = static_cast(framework()->testSettings()); return new BoostTestOutputReader(fi, app, buildDirectory(), projectFile(), diff --git a/src/plugins/autotest/boost/boosttestconfiguration.h b/src/plugins/autotest/boost/boosttestconfiguration.h index 2259eca5137..d3d4b851df4 100644 --- a/src/plugins/autotest/boost/boosttestconfiguration.h +++ b/src/plugins/autotest/boost/boosttestconfiguration.h @@ -36,7 +36,7 @@ public: explicit BoostTestConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} TestOutputReader *outputReader(const QFutureInterface &fi, - QProcess *app) const override; + Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp index 5036a683ff3..a9668fc8e80 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.cpp +++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp @@ -29,6 +29,7 @@ #include "boosttesttreeitem.h" #include +#include #include #include @@ -41,7 +42,7 @@ namespace Internal { static Q_LOGGING_CATEGORY(orLog, "qtc.autotest.boost.outputreader", QtWarningMsg) BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile, LogLevel log, ReportLevel report) @@ -51,7 +52,7 @@ BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface::of(&QProcess::finished), + connect(m_testApplication, &Utils::QtcProcess::finished, this, &BoostTestOutputReader::onFinished); } } @@ -405,7 +406,8 @@ TestResultPtr BoostTestOutputReader::createDefaultResult() const return TestResultPtr(result); } -void BoostTestOutputReader::onFinished(int exitCode, QProcess::ExitStatus /*exitState*/) { +void BoostTestOutputReader::onFinished() { + int exitCode = m_testApplication->exitCode(); if (m_reportLevel == ReportLevel::No && m_testCaseCount != -1) { int reportedFailsAndSkips = m_summary[ResultType::Fail] + m_summary[ResultType::Skip]; m_summary.insert(ResultType::Pass, m_testCaseCount - reportedFailsAndSkips); diff --git a/src/plugins/autotest/boost/boosttestoutputreader.h b/src/plugins/autotest/boost/boosttestoutputreader.h index 56527fa6271..b5cab378a7c 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.h +++ b/src/plugins/autotest/boost/boosttestoutputreader.h @@ -39,7 +39,7 @@ class BoostTestOutputReader : public TestOutputReader Q_OBJECT public: BoostTestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, const Utils::FilePath &buildDirectory, + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile, LogLevel log, ReportLevel report); protected: void processOutputLine(const QByteArray &outputLine) override; @@ -47,7 +47,7 @@ protected: TestResultPtr createDefaultResult() const override; private: - void onFinished(int exitCode, QProcess::ExitStatus /*exitState*/); + void onFinished(); void sendCompleteInformation(); void handleMessageMatch(const QRegularExpressionMatch &match); void reportNoOutputFinish(const QString &description, ResultType type); diff --git a/src/plugins/autotest/catch/catchcodeparser.cpp b/src/plugins/autotest/catch/catchcodeparser.cpp index c1368c1aa72..350b34f5dc6 100644 --- a/src/plugins/autotest/catch/catchcodeparser.cpp +++ b/src/plugins/autotest/catch/catchcodeparser.cpp @@ -90,22 +90,24 @@ void CatchCodeParser::handleIdentifier() QTC_ASSERT(m_currentIndex < m_tokens.size(), return); const Token &token = m_tokens.at(m_currentIndex); const QByteArray &identifier = m_source.mid(int(token.bytesBegin()), int(token.bytes())); - if (identifier == "TEST_CASE") { + const QByteArray unprefixed = identifier.startsWith("CATCH_") ? identifier.mid(6) : identifier; + + if (unprefixed == "TEST_CASE") { handleTestCase(false); - } else if (identifier == "SCENARIO") { + } else if (unprefixed == "SCENARIO") { handleTestCase(true); - } else if (identifier == "TEMPLATE_TEST_CASE" || identifier == "TEMPLATE_PRODUCT_TEST_CASE" - || identifier == "TEMPLATE_LIST_TEST_CASE" || identifier == "TEMPLATE_TEST_CASE_SIG" - || identifier == "TEMPLATE_PRODUCT_TEST_CASE_SIG") { + } else if (unprefixed == "TEMPLATE_TEST_CASE" || unprefixed == "TEMPLATE_PRODUCT_TEST_CASE" + || unprefixed == "TEMPLATE_LIST_TEST_CASE" || unprefixed == "TEMPLATE_TEST_CASE_SIG" + || unprefixed == "TEMPLATE_PRODUCT_TEST_CASE_SIG") { handleParameterizedTestCase(false); - } else if (identifier == "TEST_CASE_METHOD") { + } else if (unprefixed == "TEST_CASE_METHOD") { handleFixtureOrRegisteredTestCase(true); - } else if (identifier == "TEMPLATE_TEST_CASE_METHOD_SIG" - || identifier == "TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG" - || identifier == "TEMPLATE_TEST_CASE_METHOD" - || identifier == "TEMPLATE_LIST_TEST_CASE_METHOD") { + } else if (unprefixed == "TEMPLATE_TEST_CASE_METHOD_SIG" + || unprefixed == "TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG" + || unprefixed == "TEMPLATE_TEST_CASE_METHOD" + || unprefixed == "TEMPLATE_LIST_TEST_CASE_METHOD") { handleParameterizedTestCase(true); - } else if (identifier == "METHOD_AS_TEST_CASE" || identifier == "REGISTER_TEST_CASE") { + } else if (unprefixed == "METHOD_AS_TEST_CASE" || unprefixed == "REGISTER_TEST_CASE") { handleFixtureOrRegisteredTestCase(false); } } diff --git a/src/plugins/autotest/catch/catchconfiguration.cpp b/src/plugins/autotest/catch/catchconfiguration.cpp index bb1353ff4a9..7d374413a51 100644 --- a/src/plugins/autotest/catch/catchconfiguration.cpp +++ b/src/plugins/autotest/catch/catchconfiguration.cpp @@ -35,7 +35,8 @@ namespace Autotest { namespace Internal { -TestOutputReader *CatchConfiguration::outputReader(const QFutureInterface &fi, QProcess *app) const +TestOutputReader *CatchConfiguration::outputReader(const QFutureInterface &fi, + Utils::QtcProcess *app) const { return new CatchOutputReader(fi, app, buildDirectory(), projectFile()); } @@ -97,7 +98,7 @@ QStringList CatchConfiguration::argumentsForTestRunner(QStringList *omitted) con { QStringList arguments; if (testCaseCount()) - arguments << "\"" + testCases().join("\",\"") + "\""; + arguments << "\"" + testCases().join("\", \"") + "\""; arguments << "--reporter" << "xml"; if (AutotestPlugin::settings()->processArgs) { diff --git a/src/plugins/autotest/catch/catchconfiguration.h b/src/plugins/autotest/catch/catchconfiguration.h index 2a198558098..ef3549514b5 100644 --- a/src/plugins/autotest/catch/catchconfiguration.h +++ b/src/plugins/autotest/catch/catchconfiguration.h @@ -34,7 +34,7 @@ class CatchConfiguration : public DebuggableTestConfiguration public: CatchConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} TestOutputReader *outputReader(const QFutureInterface &fi, - QProcess *app) const override; + Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/catch/catchoutputreader.cpp b/src/plugins/autotest/catch/catchoutputreader.cpp index f7ae4d3bc8f..f788aea017c 100644 --- a/src/plugins/autotest/catch/catchoutputreader.cpp +++ b/src/plugins/autotest/catch/catchoutputreader.cpp @@ -49,7 +49,8 @@ namespace CatchXml { } CatchOutputReader::CatchOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, const Utils::FilePath &buildDirectory, + Utils::QtcProcess *testApplication, + const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile) : TestOutputReader (futureInterface, testApplication, buildDirectory) , m_projectFile(projectFile) diff --git a/src/plugins/autotest/catch/catchoutputreader.h b/src/plugins/autotest/catch/catchoutputreader.h index 70158309617..86c3acbb034 100644 --- a/src/plugins/autotest/catch/catchoutputreader.h +++ b/src/plugins/autotest/catch/catchoutputreader.h @@ -39,7 +39,7 @@ class CatchOutputReader : public TestOutputReader public: CatchOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, const Utils::FilePath &buildDirectory, + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile); protected: diff --git a/src/plugins/autotest/catch/catchtestparser.cpp b/src/plugins/autotest/catch/catchtestparser.cpp index da6f6ca423a..c878da135e3 100644 --- a/src/plugins/autotest/catch/catchtestparser.cpp +++ b/src/plugins/autotest/catch/catchtestparser.cpp @@ -57,10 +57,11 @@ static bool isCatchTestCaseMacro(const QString ¯oName) static bool isCatchMacro(const QString ¯oName) { + QString unprefixed = macroName.startsWith("CATCH_") ? macroName.mid(6) : macroName; const QStringList validSectionMacros = { QStringLiteral("SECTION"), QStringLiteral("WHEN") }; - return isCatchTestCaseMacro(macroName) || validSectionMacros.contains(macroName); + return isCatchTestCaseMacro(unprefixed) || validSectionMacros.contains(unprefixed); } static bool includesCatchHeader(const CPlusPlus::Document::Ptr &doc, @@ -123,7 +124,8 @@ bool CatchTestParser::processDocument(QFutureInterface &futu const QByteArray &fileContent = getFileContent(fileName); if (!hasCatchNames(doc)) { - const QRegularExpression regex("\\b(SCENARIO|(TEMPLATE_(PRODUCT_)?)?TEST_CASE(_METHOD)?|" + const QRegularExpression regex("\\b(CATCH_)?" + "(SCENARIO|(TEMPLATE_(PRODUCT_)?)?TEST_CASE(_METHOD)?|" "TEMPLATE_TEST_CASE(_METHOD)?_SIG|" "TEMPLATE_PRODUCT_TEST_CASE(_METHOD)?_SIG|" "TEMPLATE_LIST_TEST_CASE_METHOD|METHOD_AS_TEST_CASE|" diff --git a/src/plugins/autotest/catch/catchtreeitem.cpp b/src/plugins/autotest/catch/catchtreeitem.cpp index 0108811008c..462f03dba84 100644 --- a/src/plugins/autotest/catch/catchtreeitem.cpp +++ b/src/plugins/autotest/catch/catchtreeitem.cpp @@ -37,7 +37,9 @@ namespace Internal { QString CatchTreeItem::testCasesString() const { - return m_state & CatchTreeItem::Parameterized ? QString(name() + " -*") : name(); + QString testcase = m_state & CatchTreeItem::Parameterized ? QString(name() + " -*") : name(); + // mask comma if it is part of the test case name + return testcase.replace(',', "\\,"); } static QString nonRootDisplayName(const CatchTreeItem *it) diff --git a/src/plugins/autotest/ctest/ctestconfiguration.cpp b/src/plugins/autotest/ctest/ctestconfiguration.cpp index de2a94061e1..2a1d18389fb 100644 --- a/src/plugins/autotest/ctest/ctestconfiguration.cpp +++ b/src/plugins/autotest/ctest/ctestconfiguration.cpp @@ -36,7 +36,7 @@ CTestConfiguration::CTestConfiguration(ITestBase *testBase) } TestOutputReader *CTestConfiguration::outputReader(const QFutureInterface &fi, - QProcess *app) const + Utils::QtcProcess *app) const { return new CTestOutputReader(fi, app, workingDirectory()); } diff --git a/src/plugins/autotest/ctest/ctestconfiguration.h b/src/plugins/autotest/ctest/ctestconfiguration.h index 77f7904ab31..3c62c7ea843 100644 --- a/src/plugins/autotest/ctest/ctestconfiguration.h +++ b/src/plugins/autotest/ctest/ctestconfiguration.h @@ -36,7 +36,7 @@ public: explicit CTestConfiguration(ITestBase *testBase); TestOutputReader *outputReader(const QFutureInterface &fi, - QProcess *app) const final; + Utils::QtcProcess *app) const final; }; } // namespace Internal diff --git a/src/plugins/autotest/ctest/ctestoutputreader.cpp b/src/plugins/autotest/ctest/ctestoutputreader.cpp index 93315c0bea6..e9bd1f465d3 100644 --- a/src/plugins/autotest/ctest/ctestoutputreader.cpp +++ b/src/plugins/autotest/ctest/ctestoutputreader.cpp @@ -71,7 +71,7 @@ private: }; CTestOutputReader::CTestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory) : TestOutputReader(futureInterface, testApplication, buildDirectory) { diff --git a/src/plugins/autotest/ctest/ctestoutputreader.h b/src/plugins/autotest/ctest/ctestoutputreader.h index bbec3f70c77..205325fe1f7 100644 --- a/src/plugins/autotest/ctest/ctestoutputreader.h +++ b/src/plugins/autotest/ctest/ctestoutputreader.h @@ -28,6 +28,8 @@ #include +namespace Utils { class QtcProcess; } + namespace Autotest { namespace Internal { @@ -36,7 +38,7 @@ class CTestOutputReader final : public Autotest::TestOutputReader Q_DECLARE_TR_FUNCTIONS(Autotest::Internal::CTestOutputReader) public: CTestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, const Utils::FilePath &buildDirectory); + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory); protected: void processOutputLine(const QByteArray &outputLineWithNewLine) final; diff --git a/src/plugins/autotest/gtest/gtestconfiguration.cpp b/src/plugins/autotest/gtest/gtestconfiguration.cpp index ff60f32171c..025040f54c8 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.cpp +++ b/src/plugins/autotest/gtest/gtestconfiguration.cpp @@ -38,7 +38,7 @@ namespace Autotest { namespace Internal { TestOutputReader *GTestConfiguration::outputReader(const QFutureInterface &fi, - QProcess *app) const + Utils::QtcProcess *app) const { return new GTestOutputReader(fi, app, buildDirectory(), projectFile()); } diff --git a/src/plugins/autotest/gtest/gtestconfiguration.h b/src/plugins/autotest/gtest/gtestconfiguration.h index 822ad99fd1b..3844869a4b9 100644 --- a/src/plugins/autotest/gtest/gtestconfiguration.h +++ b/src/plugins/autotest/gtest/gtestconfiguration.h @@ -37,7 +37,7 @@ public: : DebuggableTestConfiguration(framework) {} TestOutputReader *outputReader(const QFutureInterface &fi, - QProcess *app) const override; + Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index 997e7d2ddc2..0c9f0b87334 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -28,6 +28,7 @@ #include "../testtreemodel.h" #include "../testtreeitem.h" #include +#include #include #include @@ -37,18 +38,19 @@ namespace Autotest { namespace Internal { GTestOutputReader::GTestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile) : TestOutputReader(futureInterface, testApplication, buildDirectory) , m_projectFile(projectFile) { if (m_testApplication) { - connect(m_testApplication, QOverload::of(&QProcess::finished), - this, [this] (int exitCode, QProcess::ExitStatus /*exitStatus*/) { + connect(m_testApplication, &Utils::QtcProcess::finished, + this, [this]() { + int exitCode = m_testApplication->exitCode(); if (exitCode == 1 && !m_description.isEmpty()) { createAndReportResult(tr("Running tests failed.\n %1\nExecutable: %2") - .arg(m_description).arg(id()), ResultType::MessageFatal); + .arg(m_description).arg(id()), ResultType::MessageFatal); } // on Windows abort() will result in normal termination, but exit code will be set to 3 if (Utils::HostOsInfo::isWindowsHost() && exitCode == 3) diff --git a/src/plugins/autotest/gtest/gtestoutputreader.h b/src/plugins/autotest/gtest/gtestoutputreader.h index 05688a4fa2b..f6d499dbed5 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.h +++ b/src/plugins/autotest/gtest/gtestoutputreader.h @@ -38,7 +38,7 @@ class GTestOutputReader : public TestOutputReader public: GTestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, const Utils::FilePath &buildDirectory, + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile); protected: void processOutputLine(const QByteArray &outputLine) override; diff --git a/src/plugins/autotest/qtest/qttestconfiguration.cpp b/src/plugins/autotest/qtest/qttestconfiguration.cpp index 7f613702137..4ca1326ba52 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.cpp +++ b/src/plugins/autotest/qtest/qttestconfiguration.cpp @@ -38,7 +38,7 @@ namespace Autotest { namespace Internal { TestOutputReader *QtTestConfiguration::outputReader(const QFutureInterface &fi, - QProcess *app) const + Utils::QtcProcess *app) const { auto qtSettings = static_cast(framework()->testSettings()); const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value() diff --git a/src/plugins/autotest/qtest/qttestconfiguration.h b/src/plugins/autotest/qtest/qttestconfiguration.h index 8196665679c..83ac6d79a53 100644 --- a/src/plugins/autotest/qtest/qttestconfiguration.h +++ b/src/plugins/autotest/qtest/qttestconfiguration.h @@ -36,7 +36,7 @@ public: explicit QtTestConfiguration(ITestFramework *framework) : DebuggableTestConfiguration(framework) {} TestOutputReader *outputReader(const QFutureInterface &fi, - QProcess *app) const override; + Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/qtest/qttestoutputreader.cpp b/src/plugins/autotest/qtest/qttestoutputreader.cpp index a6be21019d9..fc762bbe0a4 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.cpp +++ b/src/plugins/autotest/qtest/qttestoutputreader.cpp @@ -126,7 +126,7 @@ static QString constructBenchmarkInformation(const QString &metric, double value } QtTestOutputReader::QtTestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile, OutputMode mode, TestType type) diff --git a/src/plugins/autotest/qtest/qttestoutputreader.h b/src/plugins/autotest/qtest/qttestoutputreader.h index eff84dd4642..6ceabd508b5 100644 --- a/src/plugins/autotest/qtest/qttestoutputreader.h +++ b/src/plugins/autotest/qtest/qttestoutputreader.h @@ -48,7 +48,7 @@ public: }; QtTestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, const Utils::FilePath &buildDirectory, + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory, const Utils::FilePath &projectFile, OutputMode mode, TestType type); protected: void processOutputLine(const QByteArray &outputLine) override; diff --git a/src/plugins/autotest/qtest/qttestresult.cpp b/src/plugins/autotest/qtest/qttestresult.cpp index aa16f601963..eee2697ff71 100644 --- a/src/plugins/autotest/qtest/qttestresult.cpp +++ b/src/plugins/autotest/qtest/qttestresult.cpp @@ -52,7 +52,9 @@ const QString QtTestResult::outputString(bool selected) const case ResultType::UnexpectedPass: case ResultType::BlacklistedFail: case ResultType::BlacklistedPass: - output = className + "::" + m_function; + output = className; + if (!m_function.isEmpty()) + output.append("::" + m_function); if (!m_dataTag.isEmpty()) output.append(QString(" (%1)").arg(m_dataTag)); if (selected && !desc.isEmpty()) { @@ -60,7 +62,9 @@ const QString QtTestResult::outputString(bool selected) const } break; case ResultType::Benchmark: - output = className + "::" + m_function; + output = className; + if (!m_function.isEmpty()) + output.append("::" + m_function); if (!m_dataTag.isEmpty()) output.append(QString(" (%1)").arg(m_dataTag)); if (!desc.isEmpty()) { diff --git a/src/plugins/autotest/quick/quicktestconfiguration.cpp b/src/plugins/autotest/quick/quicktestconfiguration.cpp index 8ede65e66bc..9cb1abb680e 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.cpp +++ b/src/plugins/autotest/quick/quicktestconfiguration.cpp @@ -44,7 +44,7 @@ QuickTestConfiguration::QuickTestConfiguration(ITestFramework *framework) } TestOutputReader *QuickTestConfiguration::outputReader(const QFutureInterface &fi, - QProcess *app) const + Utils::QtcProcess *app) const { auto qtSettings = static_cast(framework()->testSettings()); const QtTestOutputReader::OutputMode mode = qtSettings && qtSettings->useXMLOutput.value() diff --git a/src/plugins/autotest/quick/quicktestconfiguration.h b/src/plugins/autotest/quick/quicktestconfiguration.h index 88f94c96df9..ca74633a912 100644 --- a/src/plugins/autotest/quick/quicktestconfiguration.h +++ b/src/plugins/autotest/quick/quicktestconfiguration.h @@ -35,7 +35,7 @@ class QuickTestConfiguration : public DebuggableTestConfiguration public: explicit QuickTestConfiguration(ITestFramework *framework); TestOutputReader *outputReader(const QFutureInterface &fi, - QProcess *app) const override; + Utils::QtcProcess *app) const override; QStringList argumentsForTestRunner(QStringList *omitted = nullptr) const override; Utils::Environment filteredEnvironment(const Utils::Environment &original) const override; }; diff --git a/src/plugins/autotest/testconfiguration.h b/src/plugins/autotest/testconfiguration.h index a1a4240f3dd..e338280a954 100644 --- a/src/plugins/autotest/testconfiguration.h +++ b/src/plugins/autotest/testconfiguration.h @@ -35,9 +35,7 @@ #include #include -QT_BEGIN_NAMESPACE -class QProcess; -QT_END_NAMESPACE +namespace Utils { class QtcProcess; } namespace Autotest { namespace Internal { @@ -66,7 +64,7 @@ public: Utils::FilePath executableFilePath() const; virtual TestOutputReader *outputReader(const QFutureInterface &fi, - QProcess *app) const = 0; + Utils::QtcProcess *app) const = 0; virtual Utils::Environment filteredEnvironment(const Utils::Environment &original) const; ITestBase *testBase() const { return m_testBase; } diff --git a/src/plugins/autotest/testoutputreader.cpp b/src/plugins/autotest/testoutputreader.cpp index f2ad3bff054..fcd0ace2300 100644 --- a/src/plugins/autotest/testoutputreader.cpp +++ b/src/plugins/autotest/testoutputreader.cpp @@ -30,6 +30,7 @@ #include "testtreeitem.h" #include +#include #include #include @@ -46,11 +47,12 @@ Utils::FilePath TestOutputReader::constructSourceFilePath(const Utils::FilePath } TestOutputReader::TestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, const Utils::FilePath &buildDirectory) + Utils::QtcProcess *testApplication, + const Utils::FilePath &buildDirectory) : m_futureInterface(futureInterface) , m_testApplication(testApplication) , m_buildDir(buildDirectory) - , m_id(testApplication ? testApplication->program() : QString()) + , m_id(testApplication ? testApplication->commandLine().executable().toUserOutput() : QString()) { auto chopLineBreak = [](QByteArray line) { if (line.endsWith('\n')) @@ -61,17 +63,11 @@ TestOutputReader::TestOutputReader(const QFutureInterface &future }; if (m_testApplication) { - connect(m_testApplication, &QProcess::readyReadStandardOutput, - this, [chopLineBreak, this] () { - m_testApplication->setReadChannel(QProcess::StandardOutput); - while (m_testApplication->canReadLine()) - processStdOutput(chopLineBreak(m_testApplication->readLine())); + m_testApplication->setStdOutLineCallback([this, &chopLineBreak](const QString &line) { + processStdOutput(chopLineBreak(line.toUtf8())); }); - connect(m_testApplication, &QProcess::readyReadStandardError, - this, [chopLineBreak, this] () { - m_testApplication->setReadChannel(QProcess::StandardError); - while (m_testApplication->canReadLine()) - processStdError(chopLineBreak(m_testApplication->readLine())); + m_testApplication->setStdErrLineCallback([this, &chopLineBreak](const QString &line) { + processStdError(chopLineBreak(line.toUtf8())); }); } } diff --git a/src/plugins/autotest/testoutputreader.h b/src/plugins/autotest/testoutputreader.h index b3d7cc3476d..4f5d75b471c 100644 --- a/src/plugins/autotest/testoutputreader.h +++ b/src/plugins/autotest/testoutputreader.h @@ -29,9 +29,10 @@ #include #include -#include #include +namespace Utils { class QtcProcess; } + namespace Autotest { class TestOutputReader : public QObject @@ -39,7 +40,7 @@ class TestOutputReader : public QObject Q_OBJECT public: TestOutputReader(const QFutureInterface &futureInterface, - QProcess *testApplication, const Utils::FilePath &buildDirectory); + Utils::QtcProcess *testApplication, const Utils::FilePath &buildDirectory); virtual ~TestOutputReader(); void processStdOutput(const QByteArray &outputLine); virtual void processStdError(const QByteArray &outputLine); @@ -67,7 +68,7 @@ protected: void reportResult(const TestResultPtr &result); QFutureInterface m_futureInterface; - QProcess *m_testApplication; // not owned + Utils::QtcProcess *m_testApplication; // not owned Utils::FilePath m_buildDir; QString m_id; QHash m_summary; diff --git a/src/plugins/autotest/testrunconfiguration.h b/src/plugins/autotest/testrunconfiguration.h index 451add1fa2b..ccb6282059b 100644 --- a/src/plugins/autotest/testrunconfiguration.h +++ b/src/plugins/autotest/testrunconfiguration.h @@ -66,7 +66,7 @@ public: ProjectExplorer::Runnable r; QTC_ASSERT(m_testConfig, return r); r.command.setExecutable(m_testConfig->executableFilePath()); - r.command.setArguments(m_testConfig->argumentsForTestRunner().join(' ')); + r.command.addArgs(m_testConfig->argumentsForTestRunner().join(' '), Utils::CommandLine::Raw); r.workingDirectory = m_testConfig->workingDirectory(); r.environment = m_testConfig->environment(); return r; diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index aa930eb595e..942730ba9d8 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -90,6 +90,8 @@ TestRunner::TestRunner() { s_instance = this; + m_cancelTimer.setSingleShot(true); + connect(&m_cancelTimer, &QTimer::timeout, this, [this]() { cancelCurrent(Timeout); }); connect(&m_futureWatcher, &QFutureWatcher::resultReadyAt, this, [this](int index) { emit testResultReady(m_futureWatcher.resultAt(index)); }); connect(&m_futureWatcher, &QFutureWatcher::finished, @@ -131,16 +133,17 @@ void TestRunner::runTest(TestRunMode mode, const ITestTreeItem *item) } } -static QString processInformation(const QProcess *proc) +static QString processInformation(const QtcProcess *proc) { QTC_ASSERT(proc, return QString()); - QString information("\nCommand line: " + proc->program() + ' ' + proc->arguments().join(' ')); + const Utils::CommandLine command = proc->commandLine(); + QString information("\nCommand line: " + command.executable().toUserOutput() + ' ' + command.arguments()); QStringList important = { "PATH" }; if (Utils::HostOsInfo::isLinuxHost()) important.append("LD_LIBRARY_PATH"); else if (Utils::HostOsInfo::isMacHost()) important.append({ "DYLD_LIBRARY_PATH", "DYLD_FRAMEWORK_PATH" }); - const QProcessEnvironment &environment = proc->processEnvironment(); + const Utils::Environment &environment = proc->environment(); for (const QString &var : important) information.append('\n' + var + ": " + environment.value(var)); return information; @@ -204,34 +207,35 @@ bool TestRunner::currentConfigValid() void TestRunner::setUpProcess() { QTC_ASSERT(m_currentConfig, return); - m_currentProcess = new QProcess; - m_currentProcess->setReadChannel(QProcess::StandardOutput); + m_currentProcess = new QtcProcess; if (m_currentConfig->testBase()->type() == ITestBase::Framework) { TestConfiguration *current = static_cast(m_currentConfig); - m_currentProcess->setProgram(current->executableFilePath().toString()); + m_currentProcess->setCommand({current->executableFilePath(), {}}); } else { TestToolConfiguration *current = static_cast(m_currentConfig); - m_currentProcess->setProgram(current->commandLine().executable().toString()); + m_currentProcess->setCommand({current->commandLine().executable(), {}}); } } void TestRunner::setUpProcessEnv() { + Utils::CommandLine command = m_currentProcess->commandLine(); if (m_currentConfig->testBase()->type() == ITestBase::Framework) { TestConfiguration *current = static_cast(m_currentConfig); QStringList omitted; - m_currentProcess->setArguments(current->argumentsForTestRunner(&omitted)); + command.addArgs(current->argumentsForTestRunner(&omitted).join(' '), Utils::CommandLine::Raw); if (!omitted.isEmpty()) { const QString &details = constructOmittedDetailsString(omitted); reportResult(ResultType::MessageWarn, details.arg(current->displayName())); } } else { TestToolConfiguration *current = static_cast(m_currentConfig); - m_currentProcess->setArguments(current->commandLine().splitArguments()); + command.setArguments(current->commandLine().arguments()); } + m_currentProcess->setCommand(command); - m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory().toString()); + m_currentProcess->setWorkingDirectory(m_currentConfig->workingDirectory()); const Utils::Environment &original = m_currentConfig->environment(); Utils::Environment environment = m_currentConfig->filteredEnvironment(original); const Utils::EnvironmentItems removedVariables = Utils::filtered( @@ -243,7 +247,7 @@ void TestRunner::setUpProcessEnv() .arg(m_currentConfig->displayName()); reportResult(ResultType::MessageWarn, details); } - m_currentProcess->setProcessEnvironment(environment.toProcessEnvironment()); + m_currentProcess->setEnvironment(environment); } void TestRunner::scheduleNext() @@ -272,15 +276,16 @@ void TestRunner::scheduleNext() setUpProcessEnv(); - connect(m_currentProcess, QOverload::of(&QProcess::finished), + connect(m_currentProcess, &Utils::QtcProcess::finished, this, &TestRunner::onProcessFinished); const int timeout = AutotestPlugin::settings()->timeout; - QTimer::singleShot(timeout, m_currentProcess, [this]() { cancelCurrent(Timeout); }); + m_cancelTimer.setInterval(timeout); + m_cancelTimer.start(); - qCInfo(runnerLog) << "Command:" << m_currentProcess->program(); - qCInfo(runnerLog) << "Arguments:" << m_currentProcess->arguments(); + qCInfo(runnerLog) << "Command:" << m_currentProcess->commandLine().executable(); + qCInfo(runnerLog) << "Arguments:" << m_currentProcess->commandLine().arguments(); qCInfo(runnerLog) << "Working directory:" << m_currentProcess->workingDirectory(); - qCDebug(runnerLog) << "Environment:" << m_currentProcess->environment(); + qCDebug(runnerLog) << "Environment:" << m_currentProcess->environment().toStringList(); m_currentProcess->start(); if (!m_currentProcess->waitForStarted()) { @@ -355,7 +360,8 @@ void TestRunner::onProcessFinished() void TestRunner::resetInternalPointers() { delete m_currentOutputReader; - delete m_currentProcess; + if (m_currentProcess) + m_currentProcess->deleteLater(); delete m_currentConfig; m_currentOutputReader = nullptr; m_currentProcess = nullptr; @@ -812,6 +818,7 @@ void TestRunner::onBuildQueueFinished(bool success) void TestRunner::onFinished() { + m_cancelTimer.stop(); // if we've been canceled and we still have test configurations queued just throw them away qDeleteAll(m_selectedTests); m_selectedTests.clear(); diff --git a/src/plugins/autotest/testrunner.h b/src/plugins/autotest/testrunner.h index a95a78ab9d5..961312b6410 100644 --- a/src/plugins/autotest/testrunner.h +++ b/src/plugins/autotest/testrunner.h @@ -32,16 +32,17 @@ #include #include #include +#include QT_BEGIN_NAMESPACE class QCheckBox; class QComboBox; class QDialogButtonBox; class QLabel; -class QProcess; QT_END_NAMESPACE namespace ProjectExplorer { class Project; } +namespace Utils { class QtcProcess; } namespace Autotest { @@ -105,7 +106,7 @@ private: bool m_executingTests = false; bool m_canceled = false; ITestConfiguration *m_currentConfig = nullptr; - QProcess *m_currentProcess = nullptr; + Utils::QtcProcess *m_currentProcess = nullptr; TestOutputReader *m_currentOutputReader = nullptr; TestRunMode m_runMode = TestRunMode::None; @@ -116,6 +117,7 @@ private: QMetaObject::Connection m_finishDebugConnect; // temporarily used for handling of switching the current target QMetaObject::Connection m_targetConnect; + QTimer m_cancelTimer; bool m_skipTargetsCheck = false; }; diff --git a/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp b/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp index a8b86a87ffd..535658f0f17 100644 --- a/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp +++ b/src/plugins/boot2qt/qdbdeployconfigurationfactory.cpp @@ -52,7 +52,6 @@ QdbDeployConfigurationFactory::QdbDeployConfigurationFactory() return prj->deploymentKnowledge() == DeploymentKnowledge::Bad && prj->hasMakeInstallEquivalent(); }); - addInitialStep(RemoteLinux::Constants::CheckForFreeDiskSpaceId); addInitialStep(Qdb::Constants::QdbStopApplicationStepId); addInitialStep(RemoteLinux::Constants::DirectUploadStepId); } diff --git a/src/plugins/boot2qt/qdbplugin.cpp b/src/plugins/boot2qt/qdbplugin.cpp index 1382954c807..711cdb50099 100644 --- a/src/plugins/boot2qt/qdbplugin.cpp +++ b/src/plugins/boot2qt/qdbplugin.cpp @@ -45,7 +45,6 @@ #include -#include #include #include #include @@ -177,8 +176,6 @@ public: QdbStopApplicationStepFactory m_stopApplicationStepFactory; QdbMakeDefaultAppStepFactory m_makeDefaultAppStepFactory; - QdbDeployStepFactory - m_checkForFreeDiskSpaceStepFactory{RemoteLinux::Constants::CheckForFreeDiskSpaceId}; QdbDeployStepFactory m_directUploadStepFactory{RemoteLinux::Constants::DirectUploadStepId}; QdbDeployStepFactory diff --git a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp index 3b26d7b82c7..675ee4e0e93 100644 --- a/src/plugins/clangcodemodel/clangcodemodelplugin.cpp +++ b/src/plugins/clangcodemodel/clangcodemodelplugin.cpp @@ -34,8 +34,6 @@ # include "test/clangfixittest.h" #endif -#include - #include #include #include @@ -45,6 +43,7 @@ #include #include +#include #include #include #include @@ -53,6 +52,9 @@ #include +#include +#include + using namespace Utils; namespace ClangCodeModel { @@ -69,10 +71,13 @@ void ClangCodeModelPlugin::generateCompilationDB() const auto projectInfo = CppModelManager::instance()->projectInfo(target->project()); if (!projectInfo) return; + FilePath baseDir = projectInfo->buildRoot(); + if (baseDir == target->project()->projectDirectory()) + baseDir = TemporaryDirectory::masterDirectoryFilePath(); QFuture task = Utils::runAsync(&Internal::generateCompilationDB, projectInfo, - projectInfo->buildRoot(), CompilationDbPurpose::Project, + baseDir, CompilationDbPurpose::Project, warningsConfigForProject(target->project()), globalClangOptions(), FilePath()); diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index 66ff519725b..a33d2863563 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -185,11 +185,6 @@ CppEditor::CppCompletionAssistProvider *ClangModelManagerSupport::completionAssi return nullptr; } -CppEditor::CppCompletionAssistProvider *ClangModelManagerSupport::functionHintAssistProvider() -{ - return nullptr; -} - void ClangModelManagerSupport::followSymbol(const CppEditor::CursorInEditor &data, const Utils::LinkHandler &processLinkCallback, bool resolveTarget, bool inNextSplit) diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index 01a4d7429ce..64db859d388 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -63,7 +63,6 @@ public: ~ClangModelManagerSupport() override; CppEditor::CppCompletionAssistProvider *completionAssistProvider() override; - CppEditor::CppCompletionAssistProvider *functionHintAssistProvider() override; TextEditor::BaseHoverHandler *createHoverHandler() override { return nullptr; } CppEditor::BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) override; diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index c970028709b..c602203a24d 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -25,8 +25,6 @@ #include "clangtoolrunner.h" -#include "clangtoolsconstants.h" - #include #include #include @@ -60,32 +58,17 @@ static QString finishedWithBadExitCode(const QString &name, int exitCode) } ClangToolRunner::ClangToolRunner(QObject *parent) - : QObject(parent), m_process(new QtcProcess) + : QObject(parent) {} -ClangToolRunner::~ClangToolRunner() -{ - if (m_process->state() != QProcess::NotRunning) { - // asking politly to terminate costs ~300 ms on windows so skip the courtasy and direct kill the process - if (HostOsInfo::isWindowsHost()) { - m_process->kill(); - m_process->waitForFinished(100); - } else { - m_process->stopProcess(); - } - } - - m_process->deleteLater(); -} - void ClangToolRunner::init(const FilePath &outputDirPath, const Environment &environment) { m_outputDirPath = outputDirPath; QTC_CHECK(!m_outputDirPath.isEmpty()); - m_process->setEnvironment(environment); - m_process->setWorkingDirectory(m_outputDirPath); // Current clang-cl puts log file into working dir. - connect(m_process, &QtcProcess::done, this, &ClangToolRunner::onProcessDone); + m_process.setEnvironment(environment); + m_process.setWorkingDirectory(m_outputDirPath); // Current clang-cl puts log file into working dir. + connect(&m_process, &QtcProcess::done, this, &ClangToolRunner::onProcessDone); } QStringList ClangToolRunner::mainToolArguments() const @@ -139,20 +122,20 @@ bool ClangToolRunner::run(const QString &fileToAnalyze, const QStringList &compi m_commandLine = {m_executable, m_argsCreator(compilerOptions)}; qCDebug(LOG).noquote() << "Starting" << m_commandLine.toUserOutput(); - m_process->setCommand(m_commandLine); - m_process->start(); + m_process.setCommand(m_commandLine); + m_process.start(); return true; } void ClangToolRunner::onProcessDone() { - if (m_process->result() == ProcessResult::StartFailed) { + if (m_process.result() == ProcessResult::StartFailed) { emit finishedWithFailure(generalProcessError(m_name), commandlineAndOutput()); - } else if (m_process->result() == ProcessResult::FinishedWithSuccess) { - qCDebug(LOG).noquote() << "Output:\n" << m_process->stdOut(); + } else if (m_process.result() == ProcessResult::FinishedWithSuccess) { + qCDebug(LOG).noquote() << "Output:\n" << m_process.stdOut(); emit finishedWithSuccess(m_fileToAnalyze); - } else if (m_process->result() == ProcessResult::FinishedWithError) { - emit finishedWithFailure(finishedWithBadExitCode(m_name, m_process->exitCode()), + } else if (m_process.result() == ProcessResult::FinishedWithError) { + emit finishedWithFailure(finishedWithBadExitCode(m_name, m_process.exitCode()), commandlineAndOutput()); } else { // == QProcess::CrashExit emit finishedWithFailure(finishedDueToCrash(m_name), commandlineAndOutput()); @@ -165,8 +148,8 @@ QString ClangToolRunner::commandlineAndOutput() const "Process Error: %2\n" "Output:\n%3") .arg(m_commandLine.toUserOutput()) - .arg(m_process->error()) - .arg(m_process->stdOut()); + .arg(m_process.error()) + .arg(m_process.stdOut()); } } // namespace Internal diff --git a/src/plugins/clangtools/clangtoolrunner.h b/src/plugins/clangtools/clangtoolrunner.h index 988aa56f48d..6df1213642b 100644 --- a/src/plugins/clangtools/clangtoolrunner.h +++ b/src/plugins/clangtools/clangtoolrunner.h @@ -28,13 +28,10 @@ #include "clangtoolslogfilereader.h" #include - -#include +#include #include -namespace Utils { class QtcProcess; } - namespace ClangTools { namespace Internal { @@ -46,7 +43,6 @@ class ClangToolRunner : public QObject public: ClangToolRunner(QObject *parent = nullptr); - ~ClangToolRunner() override; void init(const Utils::FilePath &outputDirPath, const Utils::Environment &environment); void setName(const QString &name) { m_name = name; } @@ -83,7 +79,7 @@ private: private: Utils::FilePath m_outputDirPath; - Utils::QtcProcess *m_process = nullptr; + Utils::QtcProcess m_process; QString m_name; Utils::FilePath m_executable; diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.cpp b/src/plugins/cmakeprojectmanager/builddirparameters.cpp index 57007fd635a..939920e4b82 100644 --- a/src/plugins/cmakeprojectmanager/builddirparameters.cpp +++ b/src/plugins/cmakeprojectmanager/builddirparameters.cpp @@ -28,7 +28,6 @@ #include "cmakebuildconfiguration.h" #include "cmakebuildsystem.h" #include "cmakekitinformation.h" -#include "cmakeprojectconstants.h" #include "cmakeprojectplugin.h" #include "cmakespecificsettings.h" #include "cmaketoolmanager.h" @@ -90,12 +89,6 @@ BuildDirParameters::BuildDirParameters(CMakeBuildSystem *buildSystem) if (Utils::HostOsInfo::isAnyUnixHost()) environment.set("ICECC", "no"); - CMakeSpecificSettings *settings = CMakeProjectPlugin::projectTypeSpecificSettings(); - if (!settings->ninjaPath.filePath().isEmpty()) { - const Utils::FilePath ninja = settings->ninjaPath.filePath(); - environment.appendOrSetPath(ninja.isFile() ? ninja.parentDir() : ninja); - } - cmakeToolId = CMakeKitAspect::cmakeToolId(k); } @@ -109,8 +102,5 @@ CMakeTool *BuildDirParameters::cmakeTool() const return CMakeToolManager::findById(cmakeToolId); } -BuildDirParameters::BuildDirParameters(const BuildDirParameters &) = default; -BuildDirParameters &BuildDirParameters::operator=(const BuildDirParameters &) = default; - } // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/builddirparameters.h b/src/plugins/cmakeprojectmanager/builddirparameters.h index 64666d3c65a..354a18678fe 100644 --- a/src/plugins/cmakeprojectmanager/builddirparameters.h +++ b/src/plugins/cmakeprojectmanager/builddirparameters.h @@ -25,14 +25,10 @@ #pragma once -#include "cmakeconfigitem.h" #include "cmaketool.h" #include -#include -#include - -#include +#include namespace CMakeProjectManager { namespace Internal { @@ -44,8 +40,6 @@ class BuildDirParameters public: BuildDirParameters(); explicit BuildDirParameters(CMakeBuildSystem *buildSystem); - BuildDirParameters(const BuildDirParameters &other); - BuildDirParameters &operator=(const BuildDirParameters &other); bool isValid() const; CMakeTool *cmakeTool() const; diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp index e8ebeda2f66..80b0f67e2cb 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp @@ -379,7 +379,16 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildSystem *bs) : } connect(m_buildSystem, &BuildSystem::parsingFinished, this, [this] { - m_configModel->setConfiguration(m_buildSystem->configurationFromCMake()); + const CMakeConfig config = m_buildSystem->configurationFromCMake(); + auto qmlDebugAspect = m_buildSystem->buildConfiguration() + ->aspect(); + const TriState qmlDebugSetting = qmlDebugAspect->value(); + bool qmlDebugConfig = CMakeBuildConfiguration::hasQmlDebugging(config); + if ((qmlDebugSetting == TriState::Enabled && !qmlDebugConfig) + || (qmlDebugSetting == TriState::Disabled && qmlDebugConfig)) { + qmlDebugAspect->setValue(TriState::Default); + } + m_configModel->setConfiguration(config); m_configModel->setInitialParametersConfiguration( m_buildSystem->initialCMakeConfiguration()); m_buildSystem->filterConfigArgumentsFromAdditionalCMakeArguments(); @@ -738,7 +747,8 @@ void CMakeBuildSettingsWidget::updateButtonState() } else { m_reconfigureButton->setText(tr("Run CMake")); } - reconfigureButtonFont.setBold(m_configModel->hasChanges(isInitial)); + reconfigureButtonFont.setBold(isInitial ? m_configModel->hasChanges(isInitial) + : !configChanges.isEmpty()); } m_reconfigureButton->setFont(reconfigureButtonFont); @@ -1388,6 +1398,16 @@ bool CMakeBuildConfiguration::isIos(const Kit *k) || deviceType == Ios::Constants::IOS_SIMULATOR_TYPE; } +bool CMakeBuildConfiguration::hasQmlDebugging(const CMakeConfig &config) +{ + // Determine QML debugging flags. This must match what we do in + // CMakeBuildSettingsWidget::getQmlDebugCxxFlags() + // such that in doubt we leave the QML Debugging setting at "Leave at default" + const QString cxxFlagsInit = config.stringValueOf("CMAKE_CXX_FLAGS_INIT"); + const QString cxxFlags = config.stringValueOf("CMAKE_CXX_FLAGS"); + return cxxFlagsInit.contains("-DQT_QML_DEBUG") && cxxFlags.contains("-DQT_QML_DEBUG"); +} + void CMakeBuildConfiguration::buildTarget(const QString &buildTarget) { auto cmBs = qobject_cast(findOrDefault( @@ -1694,6 +1714,15 @@ FilePath CMakeBuildConfiguration::sourceDirectory() const return aspect()->filePath(); } +void CMakeBuildConfiguration::addToEnvironment(Utils::Environment &env) const +{ + CMakeSpecificSettings *settings = CMakeProjectPlugin::projectTypeSpecificSettings(); + if (!settings->ninjaPath.filePath().isEmpty()) { + const Utils::FilePath ninja = settings->ninjaPath.filePath(); + env.appendOrSetPath(ninja.isFile() ? ninja.parentDir() : ninja); + } +} + QString CMakeBuildSystem::cmakeBuildType() const { auto setBuildTypeFromConfig = [this](const CMakeConfig &config) { diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h index 3121cbcc6fe..7d279b1bba1 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.h @@ -55,6 +55,7 @@ public: shadowBuildDirectory(const Utils::FilePath &projectFilePath, const ProjectExplorer::Kit *k, const QString &bcName, BuildConfiguration::BuildType buildType); static bool isIos(const ProjectExplorer::Kit *k); + static bool hasQmlDebugging(const CMakeConfig &config); // Context menu action: void buildTarget(const QString &buildTarget); @@ -63,6 +64,8 @@ public: void setSourceDirectory(const Utils::FilePath& path); Utils::FilePath sourceDirectory() const; + void addToEnvironment(Utils::Environment &env) const override; + signals: void signingFlagsChanged(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp index 0ce9e360e29..5add4f4e559 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.cpp @@ -36,26 +36,31 @@ #include "cmakeprojectplugin.h" #include "cmakespecificsettings.h" #include "projecttreehelper.h" -#include "utils/algorithm.h" #include + #include #include + #include #include #include + +#include #include #include #include #include #include #include + #include #include #include #include +#include #include #include #include @@ -1314,5 +1319,31 @@ void CMakeBuildSystem::updateInitialCMakeExpandableVars() emit configurationChanged(config); } +MakeInstallCommand CMakeBuildSystem::makeInstallCommand(const FilePath &installRoot) const +{ + MakeInstallCommand cmd; + if (CMakeTool *tool = CMakeKitAspect::cmakeTool(target()->kit())) + cmd.command.setExecutable(tool->cmakeExecutable()); + + QString installTarget = "install"; + if (usesAllCapsTargets()) + installTarget = "INSTALL"; + + FilePath buildDirectory = "."; + if (auto bc = buildConfiguration()) + buildDirectory = bc->buildDirectory(); + + cmd.command.addArg("--build"); + cmd.command.addArg(buildDirectory.onDevice(cmd.command.executable()).path()); + cmd.command.addArg("--target"); + cmd.command.addArg(installTarget); + + if (isMultiConfigReader()) + cmd.command.addArgs({"--config", cmakeBuildType()}); + + cmd.environment.set("DESTDIR", installRoot.nativePath()); + return cmd; +} + } // namespace Internal } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h index bb505b65f34..5ebfd6dfbe0 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsystem.h +++ b/src/plugins/cmakeprojectmanager/cmakebuildsystem.h @@ -98,6 +98,9 @@ public: Utils::CommandLine commandLineForTests(const QList &tests, const QStringList &options) const final; + ProjectExplorer::MakeInstallCommand makeInstallCommand( + const Utils::FilePath &installRoot) const final; + static bool filteredOutTarget(const CMakeBuildTarget &target); bool isMultiConfig() const; diff --git a/src/plugins/cmakeprojectmanager/cmakeparser.cpp b/src/plugins/cmakeprojectmanager/cmakeparser.cpp index 3da9a18b49a..addde5fd239 100644 --- a/src/plugins/cmakeprojectmanager/cmakeparser.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeparser.cpp @@ -64,6 +64,13 @@ void CMakeParser::setSourceDirectory(const QString &sourceDir) OutputLineParser::Result CMakeParser::handleLine(const QString &line, OutputFormat type) { + if (line.startsWith("ninja: build stopped")) { + m_lastTask = BuildSystemTask(Task::Error, line); + m_lines = 1; + flush(); + return Status::Done; + } + if (type != StdErrFormat) return Status::NotHandled; diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.cpp b/src/plugins/cmakeprojectmanager/cmakeproject.cpp index 445e9b1ab3b..ee6696b0e62 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeproject.cpp @@ -116,40 +116,4 @@ ProjectExplorer::DeploymentKnowledge CMakeProject::deploymentKnowledge() const : DeploymentKnowledge::Bad; } -MakeInstallCommand CMakeProject::makeInstallCommand(const Target *target, - const FilePath &installRoot) -{ - MakeInstallCommand cmd; - if (const BuildConfiguration * const bc = target->activeBuildConfiguration()) { - if (const auto cmakeStep = bc->buildSteps()->firstOfType()) { - if (CMakeTool *tool = CMakeKitAspect::cmakeTool(target->kit())) - cmd.command.setExecutable(tool->cmakeExecutable()); - } - } - - QString installTarget = "install"; - QStringList config; - - auto bs = qobject_cast(target->buildSystem()); - QTC_ASSERT(bs, return {}); - - if (bs->usesAllCapsTargets()) - installTarget = "INSTALL"; - if (bs->isMultiConfigReader()) - config << "--config" << bs->cmakeBuildType(); - - FilePath buildDirectory = "."; - if (auto bc = bs->buildConfiguration()) - buildDirectory = bc->buildDirectory(); - - cmd.command.addArg("--build"); - cmd.command.addArg(buildDirectory.onDevice(cmd.command.executable()).path()); - cmd.command.addArg("--target"); - cmd.command.addArg(installTarget); - cmd.command.addArgs(config); - - cmd.environment.set("DESTDIR", installRoot.nativePath()); - return cmd; -} - } // namespace CMakeProjectManager diff --git a/src/plugins/cmakeprojectmanager/cmakeproject.h b/src/plugins/cmakeprojectmanager/cmakeproject.h index a1f1db439d4..33239234046 100644 --- a/src/plugins/cmakeprojectmanager/cmakeproject.h +++ b/src/plugins/cmakeprojectmanager/cmakeproject.h @@ -54,8 +54,6 @@ protected: private: ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; - ProjectExplorer::MakeInstallCommand makeInstallCommand(const ProjectExplorer::Target *target, - const Utils::FilePath &installRoot) final; mutable Internal::CMakeProjectImporter *m_projectImporter = nullptr; diff --git a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp index 59f1d3796b0..ae970887fb7 100644 --- a/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp +++ b/src/plugins/cmakeprojectmanager/cmakeprojectimporter.cpp @@ -337,13 +337,7 @@ QList CMakeProjectImporter::examineDirectory(const FilePath &importPath, canonicalProjectDirectory.toUserOutput()); } - // Determine QML debugging flags. This must match what we do in - // CMakeBuildSettingsWidget::getQmlDebugCxxFlags() - // such that in doubt we leave the QML Debugging setting at "Leave at default" - const QString cxxFlagsInit = config.stringValueOf("CMAKE_CXX_FLAGS_INIT"); - const QString cxxFlags = config.stringValueOf("CMAKE_CXX_FLAGS"); - data->hasQmlDebugging = cxxFlagsInit.contains("-DQT_QML_DEBUG") - && cxxFlags.contains("-DQT_QML_DEBUG"); + data->hasQmlDebugging = CMakeBuildConfiguration::hasQmlDebugging(config); data->buildDirectory = importPath; data->cmakeBuildType = buildType; @@ -394,10 +388,7 @@ bool CMakeProjectImporter::matchKit(void *directoryData, const Kit *k) const if (!Utils::contains(allLanguages, [&tcd](const Id& language) {return language == tcd.language;})) continue; ToolChain *tc = ToolChainKitAspect::toolChain(k, tcd.language); - if (!tc - || !Utils::Environment::systemEnvironment() - .isSameExecutable(tc->compilerCommand().toString(), - tcd.compilerPath.toString())) { + if (!tc || !tc->matchesCompilerCommand(tcd.compilerPath)) { return false; } } diff --git a/src/plugins/coco/cocolanguageclient.cpp b/src/plugins/coco/cocolanguageclient.cpp index e360b6952f6..45cb39e9f74 100644 --- a/src/plugins/coco/cocolanguageclient.cpp +++ b/src/plugins/coco/cocolanguageclient.cpp @@ -154,15 +154,11 @@ class CocoTextMark : public TextEditor::TextMark public: CocoTextMark(const FilePath &fileName, const CocoDiagnostic &diag, const Id &clientId) : TextEditor::TextMark(fileName, diag.range().start().line() + 1, clientId) + , m_severity(diag.cocoSeverity()) { setLineAnnotation(diag.message()); setToolTip(diag.message()); - if (optional severity = diag.cocoSeverity()) { - - const TextEditor::TextStyle style = styleForSeverity(*severity); - m_annotationColor = - TextEditor::TextEditorSettings::fontSettings().formatFor(style).foreground(); - } + updateAnnotationColor(); } QColor annotationColor() const override @@ -171,6 +167,16 @@ public: : TextEditor::TextMark::annotationColor(); } + void updateAnnotationColor() + { + if (m_severity) { + const TextEditor::TextStyle style = styleForSeverity(*m_severity); + m_annotationColor = + TextEditor::TextEditorSettings::fontSettings().formatFor(style).foreground(); + } + } + + optional m_severity; QColor m_annotationColor; }; @@ -180,10 +186,22 @@ public: CocoDiagnosticManager(Client *client) : DiagnosticManager(client) { + connect(TextEditor::TextEditorSettings::instance(), + &TextEditor::TextEditorSettings::fontSettingsChanged, + this, + &CocoDiagnosticManager::fontSettingsChanged); setExtraSelectionsId("CocoExtraSelections"); } private: + void fontSettingsChanged() + { + forAllMarks([](TextEditor::TextMark *mark){ + static_cast(mark)->updateAnnotationColor(); + mark->updateMarker(); + }); + } + TextEditor::TextMark *createTextMark(const FilePath &filePath, const Diagnostic &diagnostic, bool /*isProjectFile*/) const override diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index 96234c16c33..77ada82f061 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -188,7 +188,7 @@ const char G_VIEW_PANES[] = "QtCreator.Group.View.Panes"; // Tools menu groups const char G_TOOLS_DEBUG[] = "QtCreator.Group.Tools.Debug"; -const char G_TOOLS_OPTIONS[] = "QtCreator.Group.Tools.Options"; +const char G_EDIT_PREFERENCES[] = "QtCreator.Group.Edit.Preferences"; // Window menu groups const char G_WINDOW_SIZE[] = "QtCreator.Group.Window.Size"; diff --git a/src/plugins/coreplugin/corejsextensions.cpp b/src/plugins/coreplugin/corejsextensions.cpp index b73534b25b5..a88de1020c4 100644 --- a/src/plugins/coreplugin/corejsextensions.cpp +++ b/src/plugins/coreplugin/corejsextensions.cpp @@ -32,8 +32,10 @@ #include #include +#include #include #include +#include namespace Core { namespace Internal { @@ -165,5 +167,34 @@ QString UtilsJsExtension::asciify(const QString &input) const return result; } +QString UtilsJsExtension::qtQuickVersion(const QString &filePath) const +{ + QDirIterator dirIt(Utils::FilePath::fromString(filePath).parentDir().path(), {"*.qml"}, + QDir::Files, QDirIterator::Subdirectories); + while (dirIt.hasNext()) { + Utils::FileReader reader; + if (!reader.fetch(Utils::FilePath::fromString(dirIt.next()))) + continue; + const QString data = QString::fromUtf8(reader.data()); + static const QString importString("import QtQuick"); + const int importIndex = data.indexOf(importString); + if (importIndex == -1) + continue; + const int versionIndex = importIndex + importString.length(); + const int newLineIndex = data.indexOf('\n', versionIndex); + if (newLineIndex == -1) + continue; + const QString versionString = data.mid(versionIndex, + newLineIndex - versionIndex).simplified(); + if (versionString.isEmpty()) + return {}; + const auto version = QVersionNumber::fromString(versionString); + if (version.isNull()) + return {}; + return version.toString(); + } + return QLatin1String("2.15"); +} + } // namespace Internal } // namespace Core diff --git a/src/plugins/coreplugin/corejsextensions.h b/src/plugins/coreplugin/corejsextensions.h index bbdc8762512..8a668cbd161 100644 --- a/src/plugins/coreplugin/corejsextensions.h +++ b/src/plugins/coreplugin/corejsextensions.h @@ -76,6 +76,9 @@ public: // Generate a ascii-only string: Q_INVOKABLE QString asciify(const QString &input) const; + + // Heuristic to find out which QtQuick import version to use for the given file. + Q_INVOKABLE QString qtQuickVersion(const QString &filePath) const; }; } // namespace Internal diff --git a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp index 18e13f35311..5236511adc0 100644 --- a/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp +++ b/src/plugins/coreplugin/dialogs/filepropertiesdialog.cpp @@ -152,7 +152,7 @@ void FilePropertiesDialog::refresh() m_ui->name->setText(fileInfo.fileName()); m_ui->path->setText(QDir::toNativeSeparators(fileInfo.canonicalPath())); - const Utils::MimeType mimeType = Utils::mimeTypeForFile(fileInfo); + const Utils::MimeType mimeType = Utils::mimeTypeForFile(m_filePath); m_ui->mimeType->setText(mimeType.name()); const EditorTypeList factories = IEditorFactory::preferredEditorTypes(m_filePath); diff --git a/src/plugins/coreplugin/editormanager/editormanager.cpp b/src/plugins/coreplugin/editormanager/editormanager.cpp index 34054025349..dbd4edd7fc3 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -2148,8 +2148,8 @@ void EditorManagerPrivate::updateWindowTitleForDocument(IDocument *document, QWi if (!documentName.isEmpty()) windowTitle.append(documentName); - const QString filePath = document ? document->filePath().absoluteFilePath().path() - : QString(); + const Utils::FilePath filePath = document ? document->filePath().absoluteFilePath() + : Utils::FilePath(); const QString windowTitleAddition = d->m_titleAdditionHandler ? d->m_titleAdditionHandler(filePath) : QString(); @@ -2181,7 +2181,7 @@ void EditorManagerPrivate::updateWindowTitleForDocument(IDocument *document, QWi windowTitle.append(dashSep); windowTitle.append(Core::Constants::IDE_DISPLAY_NAME); window->window()->setWindowTitle(windowTitle); - window->window()->setWindowFilePath(filePath); + window->window()->setWindowFilePath(filePath.path()); if (HostOsInfo::isMacHost()) { if (document) diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 4b722c6dce9..dbfe5849514 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -71,7 +71,7 @@ class CORE_EXPORT EditorManager : public QObject Q_OBJECT public: - using WindowTitleHandler = std::function; + using WindowTitleHandler = std::function; static EditorManager *instance(); diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 1fa6d4be141..4bd44b5dddc 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -717,14 +717,14 @@ void MainWindow::registerDefaultActions() connect(m_loggerAction, &QAction::triggered, this, [] { LoggingViewer::showLoggingView(); }); // Options Action - mtools->appendGroup(Constants::G_TOOLS_OPTIONS); - mtools->addSeparator(Constants::G_TOOLS_OPTIONS); + medit->appendGroup(Constants::G_EDIT_PREFERENCES); + medit->addSeparator(Constants::G_EDIT_PREFERENCES); - m_optionsAction = new QAction(tr("&Options..."), this); + m_optionsAction = new QAction(tr("&Preferences..."), this); m_optionsAction->setMenuRole(QAction::PreferencesRole); cmd = ActionManager::registerAction(m_optionsAction, Constants::OPTIONS); cmd->setDefaultKeySequence(QKeySequence::Preferences); - mtools->addAction(cmd, Constants::G_TOOLS_OPTIONS); + medit->addAction(cmd, Constants::G_EDIT_PREFERENCES); connect(m_optionsAction, &QAction::triggered, this, [] { ICore::showOptionsDialog(Id()); }); mwindow->addSeparator(Constants::G_WINDOW_LIST); diff --git a/src/plugins/coreplugin/patchtool.cpp b/src/plugins/coreplugin/patchtool.cpp index f49185ea0ef..d26fcba6c08 100644 --- a/src/plugins/coreplugin/patchtool.cpp +++ b/src/plugins/coreplugin/patchtool.cpp @@ -112,7 +112,8 @@ static bool runPatchHelper(const QByteArray &input, const FilePath &workingDirec QByteArray stdOut; QByteArray stdErr; if (!patchProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) { - patchProcess.stopProcess(); + patchProcess.stop(); + patchProcess.waitForFinished(); MessageManager::writeFlashing( QApplication::translate("Core::PatchTool", "A timeout occurred running \"%1\"") .arg(patch.toUserOutput())); diff --git a/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.cpp b/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.cpp index 50e8387a232..425ff3f657c 100644 --- a/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.cpp +++ b/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.cpp @@ -124,11 +124,6 @@ CppCompletionAssistProvider *BuiltinModelManagerSupport::completionAssistProvide } -CppCompletionAssistProvider *BuiltinModelManagerSupport::functionHintAssistProvider() -{ - return nullptr; -} - TextEditor::BaseHoverHandler *BuiltinModelManagerSupport::createHoverHandler() { return new CppHoverHandler; diff --git a/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.h b/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.h index e6583cb09a0..fed35cf89cc 100644 --- a/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.h +++ b/src/plugins/cppeditor/cppbuiltinmodelmanagersupport.h @@ -42,7 +42,6 @@ public: ~BuiltinModelManagerSupport() override; CppCompletionAssistProvider *completionAssistProvider() final; - CppCompletionAssistProvider *functionHintAssistProvider() override; TextEditor::BaseHoverHandler *createHoverHandler() final; BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) final; diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index aacf8ff5625..0c59d923c25 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -87,7 +87,7 @@ static FilePath fallbackClangdFilePath() { if (g_defaultClangdFilePath.exists()) return g_defaultClangdFilePath; - return "clangd"; + return Environment::systemEnvironment().searchInPath("clangd"); } void CppCodeModelSettings::fromSettings(QSettings *s) diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index edd776f5375..e7621e823ee 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -26,16 +26,13 @@ #include "cppeditordocument.h" #include "baseeditordocumentparser.h" -#include "builtineditordocumentprocessor.h" #include "cppcodeformatter.h" -#include "cppcodemodelsettings.h" #include "cppeditorconstants.h" #include "cppeditorplugin.h" #include "cppmodelmanager.h" #include "cppeditorconstants.h" #include "cppeditorplugin.h" #include "cpphighlighter.h" -#include "cppqtstyleindenter.h" #include "cppquickfixassistant.h" #include @@ -58,20 +55,17 @@ const char NO_PROJECT_CONFIGURATION[] = "NoProject"; -namespace { - -CppEditor::CppModelManager *mm() -{ - return CppEditor::CppModelManager::instance(); -} - -} // anonymous namespace - using namespace TextEditor; +using namespace Utils; namespace CppEditor { namespace Internal { +static CppEditor::CppModelManager *mm() +{ + return CppEditor::CppModelManager::instance(); +} + enum { processDocumentIntervalInMs = 150 }; class CppEditorDocumentHandleImpl : public CppEditorDocumentHandle @@ -150,24 +144,12 @@ void CppEditorDocument::setCompletionAssistProvider(TextEditor::CompletionAssist m_completionAssistProvider = nullptr; } -void CppEditorDocument::setFunctionHintAssistProvider(TextEditor::CompletionAssistProvider *provider) -{ - TextDocument::setFunctionHintAssistProvider(provider); - m_functionHintAssistProvider = nullptr; -} - CompletionAssistProvider *CppEditorDocument::completionAssistProvider() const { return m_completionAssistProvider ? m_completionAssistProvider : TextDocument::completionAssistProvider(); } -CompletionAssistProvider *CppEditorDocument::functionHintAssistProvider() const -{ - return m_functionHintAssistProvider - ? m_functionHintAssistProvider : TextDocument::functionHintAssistProvider(); -} - TextEditor::IAssistProvider *CppEditorDocument::quickFixAssistProvider() const { if (const auto baseProvider = TextDocument::quickFixAssistProvider()) @@ -223,7 +205,6 @@ void CppEditorDocument::onMimeTypeChanged() m_isObjCEnabled = (mt == QLatin1String(Constants::OBJECTIVE_C_SOURCE_MIMETYPE) || mt == QLatin1String(Constants::OBJECTIVE_CPP_SOURCE_MIMETYPE)); m_completionAssistProvider = mm()->completionAssistProvider(); - m_functionHintAssistProvider = mm()->functionHintAssistProvider(); initializeTimer(); } @@ -258,14 +239,13 @@ void CppEditorDocument::reparseWithPreferredParseContext(const QString &parseCon scheduleProcessDocument(); } -void CppEditorDocument::onFilePathChanged(const Utils::FilePath &oldPath, - const Utils::FilePath &newPath) +void CppEditorDocument::onFilePathChanged(const FilePath &oldPath, const FilePath &newPath) { Q_UNUSED(oldPath) if (!newPath.isEmpty()) { indenter()->setFileName(newPath); - setMimeType(Utils::mimeTypeForFile(newPath.toFileInfo()).name()); + setMimeType(mimeTypeForFile(newPath).name()); connect(this, &Core::IDocument::contentsChanged, this, &CppEditorDocument::scheduleProcessDocument, @@ -376,13 +356,13 @@ void CppEditorDocument::releaseResources() void CppEditorDocument::showHideInfoBarAboutMultipleParseContexts(bool show) { - const Utils::Id id = Constants::MULTIPLE_PARSE_CONTEXTS_AVAILABLE; + const Id id = Constants::MULTIPLE_PARSE_CONTEXTS_AVAILABLE; if (show) { - Utils::InfoBarEntry info(id, - tr("Note: Multiple parse contexts are available for this file. " - "Choose the preferred one from the editor toolbar."), - Utils::InfoBarEntry::GlobalSuppression::Enabled); + InfoBarEntry info(id, + tr("Note: Multiple parse contexts are available for this file. " + "Choose the preferred one from the editor toolbar."), + InfoBarEntry::GlobalSuppression::Enabled); info.removeCancelButton(); if (infoBar()->canInfoBeAdded(id)) infoBar()->addInfo(info); @@ -457,9 +437,9 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings()); } -bool CppEditorDocument::save(QString *errorString, const Utils::FilePath &filePath, bool autoSave) +bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, bool autoSave) { - Utils::ExecuteOnDestruction resetSettingsOnScopeExit; + ExecuteOnDestruction resetSettingsOnScopeExit; if (indenter()->formatOnSave() && !autoSave) { auto *layout = qobject_cast(document()->documentLayout()); diff --git a/src/plugins/cppeditor/cppeditordocument.h b/src/plugins/cppeditor/cppeditordocument.h index 471ba99c9b2..54009a04ebd 100644 --- a/src/plugins/cppeditor/cppeditordocument.h +++ b/src/plugins/cppeditor/cppeditordocument.h @@ -51,9 +51,7 @@ public: bool isObjCEnabled() const; void setCompletionAssistProvider(TextEditor::CompletionAssistProvider *provider) override; - void setFunctionHintAssistProvider(TextEditor::CompletionAssistProvider *provider) override; TextEditor::CompletionAssistProvider *completionAssistProvider() const override; - TextEditor::CompletionAssistProvider *functionHintAssistProvider() const override; TextEditor::IAssistProvider *quickFixAssistProvider() const override; void recalculateSemanticInfoDetached(); @@ -128,7 +126,6 @@ private: QScopedPointer m_processor; CppCompletionAssistProvider *m_completionAssistProvider = nullptr; - CppCompletionAssistProvider *m_functionHintAssistProvider = nullptr; // (Un)Registration in CppModelManager QScopedPointer m_editorDocumentHandle; diff --git a/src/plugins/cppeditor/cppfindreferences.cpp b/src/plugins/cppeditor/cppfindreferences.cpp index b5e88f1ccd7..44f40505d16 100644 --- a/src/plugins/cppeditor/cppfindreferences.cpp +++ b/src/plugins/cppeditor/cppfindreferences.cpp @@ -632,25 +632,6 @@ CPlusPlus::Symbol *CppFindReferences::findSymbol(const CppFindReferencesParamete return nullptr; } -Utils::optional getContainingFunctionName(const Utils::FilePath &fileName, - int line, - int column) -{ - const CPlusPlus::Snapshot snapshot = CppModelManager::instance()->snapshot(); - auto document = snapshot.document(fileName); - - // context properties need lookup inside function scope, and thus require a full check - CPlusPlus::Document::Ptr localDoc = document; - if (document->checkMode() != CPlusPlus::Document::FullCheck) { - localDoc = snapshot.documentFromSource(document->utf8Source(), document->fileName()); - localDoc->check(); - } - - auto funcName = localDoc->functionAt(line, column); - - return funcName.size() ? Utils::make_optional(funcName) : Utils::nullopt; -} - static void displayResults(SearchResult *search, QFutureWatcher *watcher, int first, @@ -665,24 +646,11 @@ static void displayResults(SearchResult *search, item.setMainRange(result.line, result.col, result.len); item.setLineText(result.lineText); item.setUserData(int(result.type)); + item.setContainingFunctionName(result.containingFunction); item.setStyle(colorStyleForUsageType(result.type)); item.setUseTextEditorFont(true); if (search->supportsReplace()) item.setSelectForReplacement(SessionManager::projectForFile(result.path)); - - // In case we're looking for a function, we need to look at the symbol near the end. This - // is needed to avoid following corner-cases: - // 1) if we're looking at the beginning of the function declaration, we can get the - // declaration of the previous function - // 2) if we're looking somewhere at the middle of the function declaration, we can still - // get the declaration of the previous function if the cursor is located at the - // namespace declaration, i.e. CppReference>|addResult(item); if (parameters.prettySymbolName.isEmpty()) @@ -777,7 +745,7 @@ restart_search: if (macro.name() == useMacro.name()) { unsigned column; const QString &lineSource = matchingLine(use.bytesBegin(), source, &column); - usages.append(CPlusPlus::Usage(fileName, lineSource, + usages.append(CPlusPlus::Usage(fileName, lineSource, {}, CPlusPlus::Usage::Type::Other, use.beginLine(), column, useMacro.nameToQString().size())); } diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index 6afbe669e60..f646631a90e 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -1620,11 +1620,6 @@ CppCompletionAssistProvider *CppModelManager::completionAssistProvider() const return d->m_builtinModelManagerSupport->completionAssistProvider(); } -CppCompletionAssistProvider *CppModelManager::functionHintAssistProvider() const -{ - return d->m_builtinModelManagerSupport->functionHintAssistProvider(); -} - TextEditor::BaseHoverHandler *CppModelManager::createHoverHandler() const { return d->m_builtinModelManagerSupport->createHoverHandler(); diff --git a/src/plugins/cppeditor/cppmodelmanager.h b/src/plugins/cppeditor/cppmodelmanager.h index 0177d43d5b7..3526bb5fbe0 100644 --- a/src/plugins/cppeditor/cppmodelmanager.h +++ b/src/plugins/cppeditor/cppmodelmanager.h @@ -162,7 +162,6 @@ public: void activateClangCodeModel(ModelManagerSupportProvider *modelManagerSupportProvider); CppCompletionAssistProvider *completionAssistProvider() const; - CppCompletionAssistProvider *functionHintAssistProvider() const; BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) const; TextEditor::BaseHoverHandler *createHoverHandler() const; diff --git a/src/plugins/cppeditor/cppmodelmanagersupport.h b/src/plugins/cppeditor/cppmodelmanagersupport.h index 5be236c5d52..2889cf7b67d 100644 --- a/src/plugins/cppeditor/cppmodelmanagersupport.h +++ b/src/plugins/cppeditor/cppmodelmanagersupport.h @@ -57,7 +57,6 @@ public: virtual ~ModelManagerSupport() = 0; virtual CppCompletionAssistProvider *completionAssistProvider() = 0; - virtual CppCompletionAssistProvider *functionHintAssistProvider() = 0; virtual TextEditor::BaseHoverHandler *createHoverHandler() = 0; virtual BaseEditorDocumentProcessor *createEditorDocumentProcessor( TextEditor::TextDocument *baseTextDocument) = 0; diff --git a/src/plugins/cppeditor/cppquickfix_test.cpp b/src/plugins/cppeditor/cppquickfix_test.cpp index 206a88ff740..6471134ec47 100644 --- a/src/plugins/cppeditor/cppquickfix_test.cpp +++ b/src/plugins/cppeditor/cppquickfix_test.cpp @@ -1745,6 +1745,16 @@ void QuickfixTest::testGeneric_data() << CppQuickFixFactoryPtr(new EscapeStringLiteral) << _(R"(const char *str = @"\xc3\xa0""f23\xd0\xb1g\xd0\xb1""1";)") << _(R"(const char *str = "àf23бgб1";)"); + QTest::newRow("AddLocalDeclaration_QTCREATORBUG-26004") + << CppQuickFixFactoryPtr(new AddLocalDeclaration) + << _("void func() {\n" + " QStringList list;\n" + " @it = list.cbegin();\n" + "}\n") + << _("void func() {\n" + " QStringList list;\n" + " auto it = list.cbegin();\n" + "}\n"); } void QuickfixTest::testGeneric() diff --git a/src/plugins/cppeditor/cppquickfixes.cpp b/src/plugins/cppeditor/cppquickfixes.cpp index c14fe66255c..42f90edf7c6 100644 --- a/src/plugins/cppeditor/cppquickfixes.cpp +++ b/src/plugins/cppeditor/cppquickfixes.cpp @@ -1617,14 +1617,35 @@ public: { CppRefactoringChanges refactoring(snapshot()); CppRefactoringFilePtr currentFile = refactoring.file(filePath()); + QString declaration = getDeclaration(); + + if (!declaration.isEmpty()) { + ChangeSet changes; + changes.replace(currentFile->startOf(binaryAST), + currentFile->endOf(simpleNameAST), + declaration); + currentFile->setChangeSet(changes); + currentFile->apply(); + } + } + +private: + QString getDeclaration() + { + CppRefactoringChanges refactoring(snapshot()); + CppRefactoringFilePtr currentFile = refactoring.file(filePath()); + Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); + + if (currentFile->cppDocument()->languageFeatures().cxx11Enabled) + return "auto " + oo.prettyName(simpleNameAST->name); TypeOfExpression typeOfExpression; typeOfExpression.init(semanticInfo().doc, snapshot(), context().bindings()); Scope *scope = currentFile->scopeAt(binaryAST->firstToken()); const QList result = - typeOfExpression(currentFile->textOf(binaryAST->right_expression).toUtf8(), - scope, - TypeOfExpression::Preprocess); + typeOfExpression(currentFile->textOf(binaryAST->right_expression).toUtf8(), + scope, + TypeOfExpression::Preprocess); if (!result.isEmpty()) { SubstitutionEnvironment env; @@ -1639,20 +1660,13 @@ public: Control *control = context().bindings()->control().data(); FullySpecifiedType tn = rewriteType(result.first().type(), &env, control); - Overview oo = CppCodeStyleSettings::currentProjectCodeStyleOverview(); - QString ty = oo.prettyType(tn, simpleNameAST->name); - if (!ty.isEmpty()) { - ChangeSet changes; - changes.replace(currentFile->startOf(binaryAST), - currentFile->endOf(simpleNameAST), - ty); - currentFile->setChangeSet(changes); - currentFile->apply(); - } + QString declaration = oo.prettyType(tn, simpleNameAST->name); + return declaration; } + + return {}; } -private: const BinaryExpressionAST *binaryAST; const SimpleNameAST *simpleNameAST; }; diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index 99f9b14e7fd..e3602fba712 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -185,6 +186,7 @@ CdbEngine::CdbEngine() : m_extensionCommandPrefix("!" QT_CREATOR_CDB_EXT ".") { m_process.setProcessMode(ProcessMode::Writer); + m_process.setUseCtrlCStub(true); setObjectName("CdbEngine"); setDebuggerName("CDB"); @@ -265,7 +267,7 @@ void CdbEngine::init() } // update source path maps from debugger start params mergeStartParametersSourcePathMap(); - QTC_ASSERT(m_process.state() != QProcess::Running, m_process.stopProcess()); + QTC_ASSERT(m_process.state() != QProcess::Running, m_process.stop()); } CdbEngine::~CdbEngine() = default; @@ -691,7 +693,7 @@ void CdbEngine::shutdownEngine() } } else { // Remote process. No can do, currently - m_process.stopProcess(); + m_process.stop(); } } @@ -707,7 +709,7 @@ void CdbEngine::processFinished() elapsedLogTime(), qPrintable(stateName(state())), m_process.exitStatus(), m_process.exitCode()); - notifyDebuggerProcessFinished(m_process.exitCode(), m_process.exitStatus(), "CDB"); + notifyDebuggerProcessFinished(m_process.resultData(), "CDB"); } void CdbEngine::detachDebugger() diff --git a/src/plugins/debugger/debuggerengine.cpp b/src/plugins/debugger/debuggerengine.cpp index e95ee836eae..884debdff44 100644 --- a/src/plugins/debugger/debuggerengine.cpp +++ b/src/plugins/debugger/debuggerengine.cpp @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -1789,14 +1790,14 @@ void DebuggerEngine::showMessage(const QString &msg, int channel, int timeout) c } } -void DebuggerEngine::notifyDebuggerProcessFinished(int exitCode, - QProcess::ExitStatus exitStatus, const QString &backendName) +void DebuggerEngine::notifyDebuggerProcessFinished(const ProcessResultData &result, + const QString &backendName) { showMessage(QString("%1 PROCESS FINISHED, status %2, exit code %3 (0x%4)") .arg(backendName) - .arg(exitStatus) - .arg(exitCode) - .arg(QString::number(exitCode, 16))); + .arg(result.m_exitStatus) + .arg(result.m_exitCode) + .arg(QString::number(result.m_exitCode, 16))); switch (state()) { case DebuggerFinished: @@ -1816,9 +1817,9 @@ void DebuggerEngine::notifyDebuggerProcessFinished(int exitCode, default: { // Initiate shutdown sequence notifyInferiorIll(); - const QString msg = exitStatus == QProcess::CrashExit ? + const QString msg = result.m_exitStatus == QProcess::CrashExit ? tr("The %1 process terminated.") : - tr("The %2 process terminated unexpectedly (exit code %1).").arg(exitCode); + tr("The %2 process terminated unexpectedly (exit code %1).").arg(result.m_exitCode); AsynchronousMessageBox::critical(tr("Unexpected %1 Exit").arg(backendName), msg.arg(backendName)); break; diff --git a/src/plugins/debugger/debuggerengine.h b/src/plugins/debugger/debuggerengine.h index 4205384cd99..64d1933201d 100644 --- a/src/plugins/debugger/debuggerengine.h +++ b/src/plugins/debugger/debuggerengine.h @@ -27,18 +27,17 @@ #include "debugger_global.h" #include "debuggerconstants.h" -#include "debuggeritem.h" #include "debuggerprotocol.h" #include "breakhandler.h" +#include "projectexplorer/abi.h" #include "threadshandler.h" #include #include #include #include -#include -#include +#include QT_BEGIN_NAMESPACE class QDebug; @@ -50,6 +49,7 @@ namespace Core { class IOptionsPage; } namespace Utils { class MacroExpander; class Perspective; +class ProcessResultData; } // Utils namespace Debugger { @@ -509,7 +509,7 @@ public: protected: void setDebuggerName(const QString &name); - void notifyDebuggerProcessFinished(int exitCode, QProcess::ExitStatus exitStatus, + void notifyDebuggerProcessFinished(const Utils::ProcessResultData &resultData, const QString &backendName); virtual void setState(DebuggerState state, bool forced = false); diff --git a/src/plugins/debugger/debuggeritem.cpp b/src/plugins/debugger/debuggeritem.cpp index c8f6bdcb7ae..a6659506468 100644 --- a/src/plugins/debugger/debuggeritem.cpp +++ b/src/plugins/debugger/debuggeritem.cpp @@ -294,7 +294,7 @@ bool DebuggerItem::addAndroidLldbPythonEnv(const Utils::FilePath &lldbCmd, Utils if (HostOsInfo::isAnyUnixHost()) { const FilePath pythonLibDir = pythonDir.pathAppended("lib"); if (pythonLibDir.exists()) - env.prependOrSet("LD_LIBRARY_PATH", pythonLibDir.toString()); + env.prependOrSetLibrarySearchPath(pythonLibDir); } return true; diff --git a/src/plugins/debugger/debuggerplugin.cpp b/src/plugins/debugger/debuggerplugin.cpp index 3accce69ebb..5de92dd4831 100644 --- a/src/plugins/debugger/debuggerplugin.cpp +++ b/src/plugins/debugger/debuggerplugin.cpp @@ -1753,6 +1753,7 @@ void DebuggerPlugin::attachExternalApplication(RunControl *rc) runControl->setTarget(rc->target()); runControl->setDisplayName(tr("Process %1").arg(pid.pid())); auto debugger = new DebuggerRunTool(runControl); + debugger->setInferiorExecutable(rc->targetFilePath()); debugger->setAttachPid(pid); debugger->setStartMode(AttachToLocalProcess); debugger->setCloseMode(DetachAtClose); diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp index c34b01d7c4f..b5985ac214a 100644 --- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp +++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp @@ -453,7 +453,6 @@ static QString findQtInstallPath(const FilePath &qmakePath) return QString(); } if (!proc.waitForFinished()) { - proc.stopProcess(); qWarning("%s: Timeout running '%s'.", Q_FUNC_INFO, qPrintable(qmakePath.toString())); return QString(); } diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index 229a1658a0b..bf62f52c829 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -4095,7 +4096,7 @@ void GdbEngine::handleGdbDone() if (m_commandTimer.isActive()) m_commandTimer.stop(); - notifyDebuggerProcessFinished(m_gdbProc.exitCode(), m_gdbProc.exitStatus(), "GDB"); + notifyDebuggerProcessFinished(m_gdbProc.resultData(), "GDB"); } void GdbEngine::abortDebuggerProcess() diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index 2168280abe3..f870ba78f40 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include #include +#include #include #include @@ -83,6 +85,7 @@ static int ¤tToken() LldbEngine::LldbEngine() { + m_lldbProc.setUseCtrlCStub(true); m_lldbProc.setProcessMode(ProcessMode::Writer); setObjectName("LldbEngine"); @@ -831,7 +834,7 @@ QString LldbEngine::errorMessage(QProcess::ProcessError error) const void LldbEngine::handleLldbFinished() { - notifyDebuggerProcessFinished(m_lldbProc.exitCode(), m_lldbProc.exitStatus(), "LLDB"); + notifyDebuggerProcessFinished(m_lldbProc.resultData(), "LLDB"); } void LldbEngine::readLldbStandardError() diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index 1b6a64c6a5c..ef6a753b23f 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -47,6 +47,9 @@ #include #include +#include +#include + #include #include #include @@ -1384,6 +1387,17 @@ void QmlEnginePrivate::scripts(int types, const QList ids, bool includeSour runCommand(cmd); } +static QString targetFile(const FilePath &original) +{ + auto projectTree = ProjectExplorer::ProjectTree::instance(); + auto node = projectTree->nodeForFile(original); + + if (auto resourceNode = dynamic_cast(node)) + return QLatin1String("qrc:") + resourceNode->qrcPath(); + + return original.fileName(); +} + void QmlEnginePrivate::setBreakpoint(const QString type, const QString target, bool enabled, int line, int column, const QString condition, int ignoreCount) @@ -1413,7 +1427,7 @@ void QmlEnginePrivate::setBreakpoint(const QString type, const QString target, cmd.arg(ENABLED, enabled); if (type == SCRIPTREGEXP) - cmd.arg(TARGET, Utils::FilePath::fromString(target).fileName()); + cmd.arg(TARGET, targetFile(FilePath::fromString(target))); else cmd.arg(TARGET, target); @@ -1841,6 +1855,12 @@ void QmlEnginePrivate::messageReceived(const QByteArray &data) QList v8Breakpoints; const QVariantList v8BreakpointIdList = breakData.value("breakpoints").toList(); + // skip debug break if no breakpoint - likely stopped in another file with same naming + if (v8BreakpointIdList.isEmpty()) { + inferiorStop = false; + continueDebugging(Continue); + } + for (const QVariant &breakpointId : v8BreakpointIdList) { const QString responseId = QString::number(breakpointId.toInt()); Breakpoint bp = engine->breakHandler()->findBreakpointByResponseId(responseId); diff --git a/src/plugins/debugger/terminal.cpp b/src/plugins/debugger/terminal.cpp index 55d6fd265e9..f2dd9b0b1de 100644 --- a/src/plugins/debugger/terminal.cpp +++ b/src/plugins/debugger/terminal.cpp @@ -213,8 +213,10 @@ void TerminalRunner::start() void TerminalRunner::stop() { - if (m_stubProc) - m_stubProc->stopProcess(); + if (m_stubProc && m_stubProc->isRunning()) { + m_stubProc->stop(); + m_stubProc->waitForFinished(); + } reportStopped(); } diff --git a/src/plugins/designer/formeditorplugin.cpp b/src/plugins/designer/formeditorplugin.cpp index ebe2f7cad38..6643a78e734 100644 --- a/src/plugins/designer/formeditorplugin.cpp +++ b/src/plugins/designer/formeditorplugin.cpp @@ -27,7 +27,6 @@ #include "formeditorfactory.h" #include "formeditorw.h" #include "formtemplatewizardpage.h" -#include "formwindoweditor.h" #ifdef CPP_ENABLED # include "cpp/formclasswizard.h" @@ -58,6 +57,7 @@ using namespace Core; using namespace Designer::Constants; +using namespace Utils; namespace Designer { namespace Internal { @@ -141,24 +141,24 @@ void FormEditorPlugin::extensionsInitialized() //////////////////////////////////////////////////// // Find out current existing editor file -static QString currentFile() +static FilePath currentFile() { if (const IDocument *document = EditorManager::currentDocument()) { - const QString fileName = document->filePath().toString(); - if (!fileName.isEmpty() && QFileInfo(fileName).isFile()) - return fileName; + const FilePath filePath = document->filePath(); + if (!filePath.isEmpty() && filePath.isFile()) + return filePath; } - return QString(); + return {}; } // Switch between form ('ui') and source file ('cpp'): // Find corresponding 'other' file, simply assuming it is in the same directory. -static QString otherFile() +static FilePath otherFile() { // Determine mime type of current file. - const QString current = currentFile(); + const FilePath current = currentFile(); if (current.isEmpty()) - return QString(); + return {}; const Utils::MimeType currentMimeType = Utils::mimeTypeForFile(current); // Determine potential suffixes of candidate files // 'ui' -> 'cpp', 'cpp/h' -> 'ui'. @@ -169,22 +169,21 @@ static QString otherFile() || currentMimeType.matchesName(CppEditor::Constants::CPP_HEADER_MIMETYPE)) { candidateSuffixes += Utils::mimeTypeForName(FORM_MIMETYPE).suffixes(); } else { - return QString(); + return {}; } // Try to find existing file with desired suffix - const QFileInfo currentFI(current); - const QString currentBaseName = currentFI.path() + '/' + currentFI.baseName() + '.'; + const FilePath currentBaseName = current.parentDir().pathAppended(current.baseName() + '.'); for (const QString &candidateSuffix : qAsConst(candidateSuffixes)) { - const QFileInfo fi(currentBaseName + candidateSuffix); - if (fi.isFile()) - return fi.absoluteFilePath(); + const FilePath filePath = currentBaseName.stringAppended(candidateSuffix); + if (filePath.isFile()) + return filePath.absoluteFilePath(); } - return QString(); + return {}; } void FormEditorPlugin::switchSourceForm() { - const auto fileToOpen = Utils::FilePath::fromString(otherFile()); + const FilePath fileToOpen = otherFile(); if (!fileToOpen.isEmpty()) EditorManager::openEditor(fileToOpen); } diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 7c450a7b90f..ca6d87e36fb 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -168,10 +168,6 @@ private: qint64 write(const QByteArray &data) override; void sendControlSignal(ControlSignal controlSignal) override; - bool waitForStarted(int msecs) override; - bool waitForReadyRead(int msecs) override; - bool waitForFinished(int msecs) override; - private: CommandLine fullLocalCommandLine(bool interactive); @@ -191,6 +187,7 @@ CommandLine DockerProcessImpl::fullLocalCommandLine(bool interactive) QStringList args; if (!m_setup.m_workingDirectory.isEmpty()) { + QTC_CHECK(DeviceManager::deviceForPath(m_setup.m_workingDirectory) == m_device); args.append({"cd", m_setup.m_workingDirectory.path()}); args.append("&&"); } @@ -288,27 +285,6 @@ void DockerProcessImpl::sendControlSignal(ControlSignal controlSignal) {"kill", {QString("-%1").arg(signal), QString("%2").arg(m_remotePID)}}); } -bool DockerProcessImpl::waitForStarted(int msecs) -{ - Q_UNUSED(msecs) - QTC_CHECK(false); - return false; -} - -bool DockerProcessImpl::waitForReadyRead(int msecs) -{ - Q_UNUSED(msecs) - QTC_CHECK(false); - return false; -} - -bool DockerProcessImpl::waitForFinished(int msecs) -{ - Q_UNUSED(msecs) - QTC_CHECK(false); - return false; -} - IDeviceWidget *DockerDevice::createWidget() { return new DockerDeviceWidget(sharedFromThis()); diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp index 8f1f990cbb9..9c835c98a5b 100644 --- a/src/plugins/git/gerrit/gerritmodel.cpp +++ b/src/plugins/git/gerrit/gerritmodel.cpp @@ -335,7 +335,8 @@ void QueryContext::errorTermination(const QString &msg) void QueryContext::terminate() { - m_process.stopProcess(); + m_process.stop(); + m_process.waitForFinished(); } void QueryContext::processDone() diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index f13c8b8c2a2..a92543dff8f 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -107,8 +107,7 @@ private: ErrorState }; - void processError(QProcess::ProcessError); - void processFinished(); + void processDone(); void processReadyReadStandardError(); void processReadyReadStandardOutput(); @@ -141,8 +140,7 @@ FetchContext::FetchContext(const QSharedPointer &change, , m_server(server) , m_state(FetchState) { - connect(&m_process, &QtcProcess::errorOccurred, this, &FetchContext::processError); - connect(&m_process, &QtcProcess::finished, this, &FetchContext::processFinished); + connect(&m_process, &QtcProcess::done, this, &FetchContext::processDone); connect(&m_process, &QtcProcess::readyReadStandardError, this, &FetchContext::processReadyReadStandardError); connect(&m_process, &QtcProcess::readyReadStandardOutput, @@ -175,29 +173,26 @@ void FetchContext::start() m_process.start(); } -void FetchContext::processFinished() +void FetchContext::processDone() { - if (m_process.exitStatus() != QProcess::NormalExit) { - handleError(tr("%1 crashed.").arg(m_git.toUserOutput())); + if (m_process.result() != ProcessResult::FinishedWithSuccess) { + handleError(m_process.exitMessage()); return; } - if (m_process.exitCode()) { - handleError(tr("%1 returned %2.").arg(m_git.toUserOutput()).arg(m_process.exitCode())); + if (m_state != FetchState) return; - } - if (m_state == FetchState) { - m_progress.setProgressValue(m_progress.progressValue() + 1); - if (m_fetchMode == FetchDisplay) - show(); - else if (m_fetchMode == FetchCherryPick) - cherryPick(); - else if (m_fetchMode == FetchCheckout) - checkout(); - m_progress.reportFinished(); - m_state = DoneState; - deleteLater(); - } + m_progress.setProgressValue(m_progress.progressValue() + 1); + if (m_fetchMode == FetchDisplay) + show(); + else if (m_fetchMode == FetchCherryPick) + cherryPick(); + else if (m_fetchMode == FetchCheckout) + checkout(); + + m_progress.reportFinished(); + m_state = DoneState; + deleteLater(); } void FetchContext::processReadyReadStandardError() @@ -226,17 +221,6 @@ void FetchContext::handleError(const QString &e) deleteLater(); } -void FetchContext::processError(QProcess::ProcessError e) -{ - if (m_progress.isCanceled()) - return; - const QString msg = tr("Error running %1: %2").arg(m_git.toUserOutput(), m_process.errorString()); - if (e == QProcess::FailedToStart) - handleError(msg); - else - VcsBase::VcsOutputWindow::appendError(msg); -} - void FetchContext::show() { const QString title = QString::number(m_change->number) + '/' @@ -259,10 +243,10 @@ void FetchContext::checkout() void FetchContext::terminate() { - m_process.stopProcess(); + m_process.stop(); + m_process.waitForFinished(); } - GerritPlugin::GerritPlugin(QObject *parent) : QObject(parent) , m_parameters(new GerritParameters) diff --git a/src/plugins/gitlab/queryrunner.cpp b/src/plugins/gitlab/queryrunner.cpp index 0e54a99a092..fe46db842e0 100644 --- a/src/plugins/gitlab/queryrunner.cpp +++ b/src/plugins/gitlab/queryrunner.cpp @@ -137,7 +137,8 @@ void QueryRunner::start() void QueryRunner::terminate() { - m_process.stopProcess(); + m_process.stop(); + m_process.waitForFinished(); } void QueryRunner::errorTermination(const QString &msg) diff --git a/src/plugins/help/litehtmlhelpviewer.cpp b/src/plugins/help/litehtmlhelpviewer.cpp index 61139aacbd1..4e1c697bed2 100644 --- a/src/plugins/help/litehtmlhelpviewer.cpp +++ b/src/plugins/help/litehtmlhelpviewer.cpp @@ -205,11 +205,14 @@ void LiteHtmlHelpViewer::backward() { goBackward(1); } + void LiteHtmlHelpViewer::goForward(int count) { + const int steps = qMin(count, int(m_forwardItems.size())); + if (steps == 0) + return; HistoryItem nextItem = currentHistoryItem(); - for (int i = 0; i < count; ++i) { - QTC_ASSERT(!m_forwardItems.empty(), return ); + for (int i = 0; i < steps; ++i) { m_backItems.push_back(nextItem); nextItem = m_forwardItems.front(); m_forwardItems.erase(m_forwardItems.begin()); @@ -221,9 +224,11 @@ void LiteHtmlHelpViewer::goForward(int count) void LiteHtmlHelpViewer::goBackward(int count) { + const int steps = qMin(count, int(m_backItems.size())); + if (steps == 0) + return; HistoryItem previousItem = currentHistoryItem(); - for (int i = 0; i < count; ++i) { - QTC_ASSERT(!m_backItems.empty(), return ); + for (int i = 0; i < steps; ++i) { m_forwardItems.insert(m_forwardItems.begin(), previousItem); previousItem = m_backItems.back(); m_backItems.pop_back(); @@ -247,6 +252,15 @@ bool LiteHtmlHelpViewer::eventFilter(QObject *src, QEvent *e) e->ignore(); return true; } + } else if (e->type() == QEvent::MouseButtonPress) { + auto me = static_cast(e); + if (me->button() == Qt::BackButton) { + goBackward(1); + return true; + } else if (me->button() == Qt::ForwardButton) { + goForward(1); + return true; + } } return HelpViewer::eventFilter(src, e); } diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp index 7cf1e6ad1d4..00fece4880a 100644 --- a/src/plugins/ios/iostoolhandler.cpp +++ b/src/plugins/ios/iostoolhandler.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -702,10 +703,14 @@ void IosDeviceToolHandlerPrivate::requestTransferApp(const QString &bundlePath, { m_bundlePath = bundlePath; m_deviceId = deviceId; + QString tmpDeltaPath = Utils::TemporaryDirectory::masterDirectoryFilePath().pathAppended("ios").toString(); QStringList args; args << QLatin1String("--id") << deviceId << QLatin1String("--bundle") << bundlePath << QLatin1String("--timeout") << QString::number(timeout) - << QLatin1String("--install"); + << QLatin1String("--install") + << QLatin1String("--delta-path") + << tmpDeltaPath; + start(IosToolHandler::iosDeviceToolPath(), args); } diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 0186921b88a..303436a7ff4 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -896,8 +896,7 @@ void Client::setShadowDocument(const Utils::FilePath &filePath, const QString &c return; const auto uri = DocumentUri::fromFilePath(filePath); if (isNew) { - const QString mimeType = mimeTypeForFile( - filePath.toString(), MimeMatchMode::MatchExtension).name(); + const QString mimeType = mimeTypeForFile(filePath, MimeMatchMode::MatchExtension).name(); d->sendOpenNotification(filePath, mimeType, content, 0); } diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp index 4ebb7f6c304..e81bda7bd8a 100644 --- a/src/plugins/languageclient/diagnosticmanager.cpp +++ b/src/plugins/languageclient/diagnosticmanager.cpp @@ -176,6 +176,14 @@ void DiagnosticManager::setExtraSelectionsId(const Utils::Id &extraSelectionsId) m_extraSelectionsId = extraSelectionsId; } +void DiagnosticManager::forAllMarks(std::function func) +{ + for (const Marks &marks : qAsConst(m_marks)) { + for (TextEditor::TextMark *mark : marks.marks) + func(mark); + } +} + void DiagnosticManager::clearDiagnostics() { for (const DocumentUri &uri : m_diagnostics.keys()) diff --git a/src/plugins/languageclient/diagnosticmanager.h b/src/plugins/languageclient/diagnosticmanager.h index aa229b91c00..282a5c3d065 100644 --- a/src/plugins/languageclient/diagnosticmanager.h +++ b/src/plugins/languageclient/diagnosticmanager.h @@ -85,6 +85,8 @@ protected: void setExtraSelectionsId(const Utils::Id &extraSelectionsId); + void forAllMarks(std::function func); + private: struct VersionedDiagnostics { diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index e9e8ad64533..e10729987ce 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -233,7 +233,7 @@ public: // GenericProposalModel interface bool containsDuplicates() const override { return false; } bool isSortable(const QString &/*prefix*/) const override; - void sort(const QString &/*prefix*/) override; + void sort(const QString &prefix) override; bool supportsPrefixExpansion() const override { return false; } QList items() const { return m_currentItems; } @@ -247,19 +247,21 @@ bool LanguageClientCompletionModel::isSortable(const QString &) const }); } -void LanguageClientCompletionModel::sort(const QString &/*prefix*/) +void LanguageClientCompletionModel::sort(const QString &prefix) { std::sort(m_currentItems.begin(), m_currentItems.end(), - [] (AssistProposalItemInterface *a, AssistProposalItemInterface *b){ + [&prefix] (AssistProposalItemInterface *a, AssistProposalItemInterface *b){ const auto lca = dynamic_cast(a); const auto lcb = dynamic_cast(b); if (!lca && !lcb) return a->text() < b->text(); if (lca && lcb) return *lca < *lcb; - if (lca && !lcb) - return true; - return false; + if (prefix.isEmpty()) + return lca && !lcb; + if (!lca) + return a->text().toLower().startsWith(prefix.toLower()); + return !b->text().toLower().startsWith(prefix.toLower()); }); } diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index 49d0699a665..5b7431cda00 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -105,15 +105,13 @@ StdIOClientInterface::StdIOClientInterface() StdIOClientInterface::~StdIOClientInterface() { - if (m_process) - m_process->stopProcess(); delete m_process; } void StdIOClientInterface::startImpl() { if (m_process) { - QTC_ASSERT(!m_process->isRunning(), m_process->stopProcess() ); + QTC_CHECK(!m_process->isRunning()); delete m_process; } m_process = new Utils::QtcProcess; diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp index c72e145710f..ab9d1655e98 100644 --- a/src/plugins/mcusupport/mcusupportsdk.cpp +++ b/src/plugins/mcusupport/mcusupportsdk.cpp @@ -433,7 +433,7 @@ static McuPackagePtr createCypressProgrammerPackage(const SettingsHandler::Ptr & static McuPackagePtr createRenesasProgrammerPackage(const SettingsHandler::Ptr &settingsHandler) { - const char envVar[] = "RenesasFlashProgrammer_PATH"; + const char envVar[] = "RENESAS_FLASH_PROGRAMMER_PATH"; FilePath defaultPath; if (qEnvironmentVariableIsSet(envVar)) { diff --git a/src/plugins/mesonprojectmanager/project/mesonprocess.cpp b/src/plugins/mesonprojectmanager/project/mesonprocess.cpp index e457a9c379b..f8561ecbee7 100644 --- a/src/plugins/mesonprojectmanager/project/mesonprocess.cpp +++ b/src/plugins/mesonprojectmanager/project/mesonprocess.cpp @@ -52,7 +52,7 @@ MesonProcess::MesonProcess() } bool MesonProcess::run(const Command &command, - const Utils::Environment env, + const Environment &env, const QString &projectName, bool captureStdo) { @@ -97,58 +97,25 @@ void MesonProcess::setProgressValue(int p) m_future.setProgressValue(p); } -void MesonProcess::handleProcessFinished(int code, QProcess::ExitStatus status) +void MesonProcess::handleProcessDone() { + if (m_process->result() != ProcessResult::FinishedWithSuccess) { + ProjectExplorer::TaskHub::addTask(ProjectExplorer::BuildSystemTask{ + ProjectExplorer::Task::TaskType::Error, m_process->exitMessage()}); + } m_cancelTimer.stop(); m_stdo = m_process->readAllStandardOutput(); m_stderr = m_process->readAllStandardError(); - if (status == QProcess::NormalExit) { + if (m_process->exitStatus() == QProcess::NormalExit) { m_future.setProgressValue(1); m_future.reportFinished(); } else { m_future.reportCanceled(); m_future.reportFinished(); } - const QString elapsedTime = Utils::formatElapsedTime(m_elapsed.elapsed()); + const QString elapsedTime = formatElapsedTime(m_elapsed.elapsed()); Core::MessageManager::writeSilently(elapsedTime); - emit finished(code, status); -} - -void MesonProcess::handleProcessError(QProcess::ProcessError error) -{ - QString message; - QString commandStr = m_currentCommand.toUserOutput(); - switch (error) { - case QProcess::FailedToStart: - message = tr("The process failed to start.") - + tr("Either the " - "invoked program \"%1\" is missing, or you may have insufficient " - "permissions to invoke the program.") - .arg(m_currentCommand.executable().toUserOutput()); - break; - case QProcess::Crashed: - message = tr("The process was ended forcefully."); - break; - case QProcess::Timedout: - message = tr("Process timed out."); - break; - case QProcess::WriteError: - message = tr("An error occurred when attempting to write " - "to the process. For example, the process may not be running, " - "or it may have closed its input channel."); - break; - case QProcess::ReadError: - message = tr("An error occurred when attempting to read from " - "the process. For example, the process may not be running."); - break; - case QProcess::UnknownError: - message = tr("An unknown error in the process occurred."); - break; - } - ProjectExplorer::TaskHub::addTask( - ProjectExplorer::BuildSystemTask{ProjectExplorer::Task::TaskType::Error, - QString("%1\n%2").arg(message).arg(commandStr)}); - handleProcessFinished(-1, QProcess::CrashExit); + emit finished(m_process->exitCode(), m_process->exitStatus()); } void MesonProcess::checkForCancelled() @@ -161,26 +128,16 @@ void MesonProcess::checkForCancelled() } void MesonProcess::setupProcess(const Command &command, - const Utils::Environment env, + const Environment env, bool captureStdo) { - if (m_process) - disconnect(m_process.get()); - m_process = std::make_unique(); - connect(m_process.get(), &QtcProcess::finished, this, [this] { - handleProcessFinished(m_process->exitCode(), m_process->exitStatus()); - }); - connect(m_process.get(), &QtcProcess::errorOccurred, this, &MesonProcess::handleProcessError); + m_process.reset(new QtcProcess); + connect(m_process.get(), &QtcProcess::done, this, &MesonProcess::handleProcessDone); if (!captureStdo) { - connect(m_process.get(), - &QtcProcess::readyReadStandardOutput, - this, - &MesonProcess::processStandardOutput); - - connect(m_process.get(), - &QtcProcess::readyReadStandardError, - this, - &MesonProcess::processStandardError); + connect(m_process.get(), &QtcProcess::readyReadStandardOutput, + this, &MesonProcess::processStandardOutput); + connect(m_process.get(), &QtcProcess::readyReadStandardError, + this, &MesonProcess::processStandardError); } m_process->setWorkingDirectory(command.workDir()); @@ -213,17 +170,15 @@ bool MesonProcess::sanityCheck(const Command &command) const void MesonProcess::processStandardOutput() { - QTC_ASSERT(m_process, return ); - auto data = m_process->readAllStandardOutput(); + const auto data = m_process->readAllStandardOutput(); Core::MessageManager::writeSilently(QString::fromLocal8Bit(data)); emit readyReadStandardOutput(data); } void MesonProcess::processStandardError() { - QTC_ASSERT(m_process, return ); - Core::MessageManager::writeSilently(QString::fromLocal8Bit(m_process->readAllStandardError())); } + } // namespace Internal } // namespace MesonProjectManager diff --git a/src/plugins/mesonprojectmanager/project/mesonprocess.h b/src/plugins/mesonprojectmanager/project/mesonprocess.h index f4c191af933..d1ee043781c 100644 --- a/src/plugins/mesonprojectmanager/project/mesonprocess.h +++ b/src/plugins/mesonprojectmanager/project/mesonprocess.h @@ -47,7 +47,7 @@ class MesonProcess final : public QObject public: MesonProcess(); bool run(const Command &command, - const Utils::Environment env, + const Utils::Environment &env, const QString &projectName, bool captureStdo = false); @@ -66,8 +66,7 @@ signals: void readyReadStandardOutput(const QByteArray &data); private: - void handleProcessFinished(int code, QProcess::ExitStatus status); - void handleProcessError(QProcess::ProcessError error); + void handleProcessDone(); void checkForCancelled(); void setupProcess(const Command &command, const Utils::Environment env, bool captureStdo); diff --git a/src/plugins/mesonprojectmanager/project/mesonproject.cpp b/src/plugins/mesonprojectmanager/project/mesonproject.cpp index 2406e35755f..4b770f2793f 100644 --- a/src/plugins/mesonprojectmanager/project/mesonproject.cpp +++ b/src/plugins/mesonprojectmanager/project/mesonproject.cpp @@ -77,14 +77,5 @@ ProjectExplorer::DeploymentKnowledge MesonProject::deploymentKnowledge() const return ProjectExplorer::DeploymentKnowledge::Bad; } -ProjectExplorer::MakeInstallCommand MesonProject::makeInstallCommand(const ProjectExplorer::Target *target, - const Utils::FilePath &installRoot) -{ - Q_UNUSED(target) - Q_UNUSED(installRoot) - // TODO in next releases - return {}; -} - } // namespace Internal } // namespace MesonProjectManager diff --git a/src/plugins/mesonprojectmanager/project/mesonproject.h b/src/plugins/mesonprojectmanager/project/mesonproject.h index e07b82aa56b..29920b03fa7 100644 --- a/src/plugins/mesonprojectmanager/project/mesonproject.h +++ b/src/plugins/mesonprojectmanager/project/mesonproject.h @@ -46,8 +46,6 @@ public: private: ProjectExplorer::DeploymentKnowledge deploymentKnowledge() const override; - ProjectExplorer::MakeInstallCommand makeInstallCommand(const ProjectExplorer::Target *target, - const Utils::FilePath &installRoot) final; mutable std::unique_ptr m_projectImporter; }; diff --git a/src/plugins/perforce/perforcechecker.cpp b/src/plugins/perforce/perforcechecker.cpp index 2e53d1e538e..3dc7f73d504 100644 --- a/src/plugins/perforce/perforcechecker.cpp +++ b/src/plugins/perforce/perforcechecker.cpp @@ -107,7 +107,8 @@ void PerforceChecker::slotTimeOut() if (!isRunning()) return; m_timedOut = true; - m_process.stopProcess(); + m_process.stop(); + m_process.waitForFinished(); emitFailed(tr("\"%1\" timed out after %2 ms.").arg(m_binary.toUserOutput()).arg(m_timeOutMS)); } diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index b415b219674..4c7039d2606 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -1329,7 +1329,8 @@ PerforceResponse PerforcePluginPrivate::fullySynchronousProcess(const FilePath & QByteArray stdErr; const int timeOutS = (flags & LongTimeOut) ? m_settings.longTimeOutS() : m_settings.timeOutS.value(); if (!process.readDataFromProcess(timeOutS, &stdOut, &stdErr, true)) { - process.stopProcess(); + process.stop(); + process.waitForFinished(); response.error = true; response.message = msgTimeout(timeOutS); return response; diff --git a/src/plugins/projectexplorer/buildmanager.cpp b/src/plugins/projectexplorer/buildmanager.cpp index 7116792d77c..41e27da1f23 100644 --- a/src/plugins/projectexplorer/buildmanager.cpp +++ b/src/plugins/projectexplorer/buildmanager.cpp @@ -228,6 +228,7 @@ public: QStringList m_stepNames; int m_progress = 0; int m_maxProgress = 0; + bool m_poppedUpTaskWindow = false; bool m_running = false; bool m_isDeploying = false; // is set to true while canceling, so that nextBuildStep knows that the BuildStep finished because of canceling @@ -489,6 +490,10 @@ void BuildManager::updateTaskCount() { const int errors = getErrorTaskCount(); ProgressManager::setApplicationLabel(errors > 0 ? QString::number(errors) : QString()); + if (errors > 0 && !d->m_poppedUpTaskWindow) { + showTaskWindow(); + d->m_poppedUpTaskWindow = true; + } } void BuildManager::finish() @@ -516,6 +521,7 @@ void BuildManager::clearBuildQueue() d->m_buildQueue.clear(); d->m_enabledState.clear(); d->m_running = false; + d->m_poppedUpTaskWindow = false; d->m_isDeploying = false; d->m_previousBuildStepProject = nullptr; d->m_currentBuildStep = nullptr; @@ -752,6 +758,7 @@ void BuildManager::nextStep() d->m_currentBuildStep->run(); } else { d->m_running = false; + d->m_poppedUpTaskWindow = false; d->m_isDeploying = false; d->m_previousBuildStepProject = nullptr; d->m_progressFutureInterface->reportFinished(); diff --git a/src/plugins/projectexplorer/buildsteplist.cpp b/src/plugins/projectexplorer/buildsteplist.cpp index 0a60422dbb1..d77dd327ba7 100644 --- a/src/plugins/projectexplorer/buildsteplist.cpp +++ b/src/plugins/projectexplorer/buildsteplist.cpp @@ -131,6 +131,11 @@ bool BuildStepList::fromMap(const QVariantMap &map) } bool handled = false; Utils::Id stepId = idFromMap(bsData); + + // pre-8.0 compat + if (stepId == "RemoteLinux.CheckForFreeDiskSpaceStep") + continue; + for (BuildStepFactory *factory : factories) { if (factory->stepId() == stepId) { if (factory->canHandle(this)) { @@ -196,7 +201,7 @@ void BuildStepList::moveStepUp(int position) emit stepMoved(position, position - 1); } -BuildStep *BuildStepList::at(int position) +BuildStep *BuildStepList::at(int position) const { return m_steps.at(position); } diff --git a/src/plugins/projectexplorer/buildsteplist.h b/src/plugins/projectexplorer/buildsteplist.h index 49c0f8b206b..4d55a4a023f 100644 --- a/src/plugins/projectexplorer/buildsteplist.h +++ b/src/plugins/projectexplorer/buildsteplist.h @@ -49,7 +49,7 @@ public: QList steps() const; - template BS *firstOfType() { + template BS *firstOfType() const { BS *bs = nullptr; for (int i = 0; i < count(); ++i) { bs = qobject_cast(at(i)); @@ -76,7 +76,7 @@ public: bool removeStep(int position); void moveStepUp(int position); - BuildStep *at(int position); + BuildStep *at(int position) const; Target *target() { return m_target; } diff --git a/src/plugins/projectexplorer/buildsystem.cpp b/src/plugins/projectexplorer/buildsystem.cpp index 1cfeec74c23..930416f3bef 100644 --- a/src/plugins/projectexplorer/buildsystem.cpp +++ b/src/plugins/projectexplorer/buildsystem.cpp @@ -34,7 +34,11 @@ #include #include + #include +#include +#include + #include #include @@ -253,6 +257,22 @@ bool BuildSystem::supportsAction(Node *, ProjectAction, const Node *) const return false; } +MakeInstallCommand BuildSystem::makeInstallCommand(const FilePath &installRoot) const +{ + QTC_ASSERT(target()->project()->hasMakeInstallEquivalent(), return {}); + + BuildStepList *buildSteps = buildConfiguration()->buildSteps(); + QTC_ASSERT(buildSteps, return {}); + + MakeInstallCommand cmd; + if (const auto makeStep = buildSteps->firstOfType()) { + cmd.command.setExecutable(makeStep->makeExecutable()); + cmd.command.addArg("install"); + cmd.command.addArg("INSTALL_ROOT=" + installRoot.nativePath()); + } + return cmd; +} + FilePaths BuildSystem::filesGeneratedFrom(const FilePath &sourceFile) const { Q_UNUSED(sourceFile) diff --git a/src/plugins/projectexplorer/buildsystem.h b/src/plugins/projectexplorer/buildsystem.h index 263738d8e45..e9bcd90edaf 100644 --- a/src/plugins/projectexplorer/buildsystem.h +++ b/src/plugins/projectexplorer/buildsystem.h @@ -40,6 +40,7 @@ class CommandLine; namespace ProjectExplorer { class BuildConfiguration; +class BuildStepList; class Node; struct TestCaseInfo @@ -103,6 +104,8 @@ public: virtual bool supportsAction(Node *context, ProjectAction action, const Node *node) const; virtual QString name() const = 0; + virtual MakeInstallCommand makeInstallCommand(const Utils::FilePath &installRoot) const; + virtual Utils::FilePaths filesGeneratedFrom(const Utils::FilePath &sourceFile) const; virtual QVariant additionalData(Utils::Id id) const; diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp index 1ffbdba5f71..64e9556995d 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp @@ -179,6 +179,12 @@ bool DesktopDevice::setPermissions(const FilePath &filePath, QFile::Permissions return filePath.setPermissions(permissions); } +FilePath DesktopDevice::mapToGlobalPath(const Utils::FilePath &pathOnDevice) const +{ + QTC_CHECK(!pathOnDevice.needsDevice()); + return pathOnDevice; +} + Environment DesktopDevice::systemEnvironment() const { return Environment::systemEnvironment(); diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h index 391bf53997f..37dc326a989 100644 --- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h +++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h @@ -79,6 +79,7 @@ public: qint64 fileSize(const Utils::FilePath &filePath) const override; QFile::Permissions permissions(const Utils::FilePath &filePath) const override; bool setPermissions(const Utils::FilePath &filePath, QFile::Permissions) const override; + Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const override; protected: DesktopDevice(); diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp index 13892ceb3b1..fb7ccf70460 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp @@ -153,9 +153,9 @@ void DeviceSettingsWidget::addDevice() m_deviceManager->addDevice(device); m_ui->removeConfigButton->setEnabled(true); m_ui->configurationComboBox->setCurrentIndex(m_deviceManagerModel->indexOf(device)); + saveSettings(); if (device->hasDeviceTester()) testDevice(); - saveSettings(); } void DeviceSettingsWidget::removeDevice() diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 69344b44a2c..f7ca5633bb7 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -212,7 +212,17 @@ bool IDevice::isAnyUnixDevice() const FilePath IDevice::mapToGlobalPath(const FilePath &pathOnDevice) const { - return pathOnDevice; + if (pathOnDevice.needsDevice()) { + // Already correct form, only sanity check it's ours... + QTC_CHECK(handlesFile(pathOnDevice)); + return pathOnDevice; + } + // match DeviceManager::deviceForPath + FilePath result; + result.setPath(pathOnDevice.path()); + result.setScheme("device"); + result.setHost(id().toString()); + return result; } QString IDevice::mapToDevicePath(const FilePath &globalPath) const @@ -227,7 +237,8 @@ FilePath IDevice::filePath(const QString &pathOnDevice) const bool IDevice::handlesFile(const FilePath &filePath) const { - Q_UNUSED(filePath); + if (filePath.scheme() == "device" && filePath.host() == id().toString()) + return true; return false; } diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 168062d154f..355ff2d7fc6 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -1580,6 +1580,27 @@ ClangToolChain::~ClangToolChain() QObject::disconnect(m_mingwToolchainAddedConnection); } +bool ClangToolChain::matchesCompilerCommand(const Utils::FilePath &command, + const Utils::Environment &env) const +{ + if (!m_resolvedCompilerCommand) { + m_resolvedCompilerCommand = FilePath(); + if (HostOsInfo::isMacHost() + && compilerCommand().parentDir() == FilePath::fromString("/usr/bin")) { + std::unique_ptr xcrun(new QtcProcess); + xcrun->setCommand({"/usr/bin/xcrun", {"-f", compilerCommand().fileName()}}); + xcrun->runBlocking(); + const FilePath output = FilePath::fromString(xcrun->stdOut().trimmed()); + if (output.isExecutableFile() && output != compilerCommand()) + m_resolvedCompilerCommand = output; + } + } + if (!m_resolvedCompilerCommand->isEmpty() + && env.isSameExecutable(m_resolvedCompilerCommand->toString(), command.toString())) + return true; + return GccToolChain::matchesCompilerCommand(command, env); +} + static FilePath mingwAwareMakeCommand(const Environment &environment) { const QStringList makes diff --git a/src/plugins/projectexplorer/gcctoolchain.h b/src/plugins/projectexplorer/gcctoolchain.h index 7bd83d0a1b2..bad26674e23 100644 --- a/src/plugins/projectexplorer/gcctoolchain.h +++ b/src/plugins/projectexplorer/gcctoolchain.h @@ -33,6 +33,7 @@ #include "headerpath.h" #include +#include #include #include @@ -211,6 +212,10 @@ public: explicit ClangToolChain(Utils::Id typeId); ~ClangToolChain() override; + bool matchesCompilerCommand( + const Utils::FilePath &command, + const Utils::Environment &env = Utils::Environment::systemEnvironment()) const override; + Utils::FilePath makeCommand(const Utils::Environment &environment) const override; Utils::LanguageExtensions languageExtensions(const QStringList &cxxflags) const override; @@ -237,6 +242,9 @@ protected: void syncAutodetectedWithParentToolchains(); private: + // "resolved" on macOS from /usr/bin/clang(++) etc to /usr/bin/clang(++) + // which is used for comparison with matchesCompileCommand + mutable Utils::optional m_resolvedCompilerCommand; QByteArray m_parentToolChainId; QMetaObject::Connection m_mingwToolchainAddedConnection; QMetaObject::Connection m_thisToolchainRemovedConnection; diff --git a/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp b/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp index f0d3433d23f..5ddb908baef 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonkitspage.cpp @@ -112,10 +112,8 @@ void JsonKitsPage::setupProjectFiles(const JsonWizard::GeneratorFiles &files) { for (const JsonWizard::GeneratorFile &f : files) { if (f.file.attributes() & GeneratedFile::OpenProjectAttribute) { - const QFileInfo fi(f.file.path()); - const QString path = fi.absoluteFilePath(); - Project *project = ProjectManager::openProject(Utils::mimeTypeForFile(fi), - Utils::FilePath::fromString(path)); + Project *project = ProjectManager::openProject(Utils::mimeTypeForFile(f.file.filePath()), + f.file.filePath().absoluteFilePath()); if (project) { if (setupProject(project)) project->saveSettings(); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp index 38a92e93707..624583f6dcb 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardgeneratorfactory.cpp @@ -86,7 +86,7 @@ bool JsonWizardGenerator::formatFile(const JsonWizard *wizard, GeneratedFile *fi if (file->isBinary() || file->contents().isEmpty()) return true; // nothing to do - Id languageId = TextEditorSettings::languageId(Utils::mimeTypeForFile(file->path()).name()); + Id languageId = TextEditorSettings::languageId(Utils::mimeTypeForFile(file->filePath()).name()); if (!languageId.isValid()) return true; // don't modify files like *.ui, *.pro @@ -99,7 +99,7 @@ bool JsonWizardGenerator::formatFile(const JsonWizard *wizard, GeneratedFile *fi Indenter *indenter = nullptr; if (factory) { indenter = factory->createIndenter(&doc); - indenter->setFileName(Utils::FilePath::fromString(file->path())); + indenter->setFileName(file->filePath()); } if (!indenter) indenter = new TextIndenter(&doc); diff --git a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp index 7912d5decfd..528110e8799 100644 --- a/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp +++ b/src/plugins/projectexplorer/jsonwizard/jsonwizardscannergenerator.cpp @@ -25,15 +25,12 @@ #include "jsonwizardscannergenerator.h" -#include "../projectexplorer.h" #include "../projectmanager.h" -#include "jsonwizard.h" -#include "jsonwizardfactory.h" #include #include -#include +#include #include #include #include @@ -104,7 +101,8 @@ Core::GeneratedFiles JsonWizardScannerGenerator::fileList(Utils::MacroExpander * for (auto it = result.begin(); it != result.end(); ++it) { const QString relPath = project.relativeFilePath(it->path()); it->setBinary(binaryPattern.match(relPath).hasMatch()); - bool found = ProjectManager::canOpenProjectForMimeType(Utils::mimeTypeForFile(relPath)); + bool found = ProjectManager::canOpenProjectForMimeType(Utils::mimeTypeForFile( + Utils::FilePath::fromString(relPath))); if (found) { it->setAttributes(it->attributes() | Core::GeneratedFile::OpenProjectAttribute); minDepth = std::min(minDepth, getDepth(it->path())); diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index d6eaa3bbaf7..9f456a8b06c 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -1145,7 +1145,7 @@ ToolChain::BuiltInHeaderPathsRunner MsvcToolChain::createBuiltInHeaderPathsRunne void MsvcToolChain::addToEnvironment(Utils::Environment &env) const { // We cache the full environment (incoming + modifications by setup script). - if (m_resultEnvironment.isValid() || env != m_lastEnvironment) { + if (!m_resultEnvironment.isValid() || env != m_lastEnvironment) { qCDebug(Log) << "addToEnvironment: " << displayName(); m_lastEnvironment = env; m_resultEnvironment = readEnvironmentSetting(env); diff --git a/src/plugins/projectexplorer/project.cpp b/src/plugins/projectexplorer/project.cpp index 23998359fb4..cd0c64aec34 100644 --- a/src/plugins/projectexplorer/project.cpp +++ b/src/plugins/projectexplorer/project.cpp @@ -32,11 +32,9 @@ #include "editorconfiguration.h" #include "kit.h" #include "kitinformation.h" -#include "makestep.h" #include "projectexplorer.h" #include "projectnodes.h" #include "runconfiguration.h" -#include "runcontrol.h" #include "session.h" #include "target.h" #include "taskhub.h" @@ -971,19 +969,6 @@ bool Project::hasMakeInstallEquivalent() const return d->m_hasMakeInstallEquivalent; } -MakeInstallCommand Project::makeInstallCommand(const Target *target, const FilePath &installRoot) -{ - QTC_ASSERT(hasMakeInstallEquivalent(), return MakeInstallCommand()); - MakeInstallCommand cmd; - if (const BuildConfiguration * const bc = target->activeBuildConfiguration()) { - if (const auto makeStep = bc->buildSteps()->firstOfType()) - cmd.command.setExecutable(makeStep->makeExecutable()); - } - cmd.command.addArg("install"); - cmd.command.addArg("INSTALL_ROOT=" + installRoot.nativePath()); - return cmd; -} - void Project::setup(const QList &infoList) { std::vector> toRegister; diff --git a/src/plugins/projectexplorer/project.h b/src/plugins/projectexplorer/project.h index 36cb94feeb0..039d191c1be 100644 --- a/src/plugins/projectexplorer/project.h +++ b/src/plugins/projectexplorer/project.h @@ -149,8 +149,6 @@ public: virtual DeploymentKnowledge deploymentKnowledge() const { return DeploymentKnowledge::Bad; } bool hasMakeInstallEquivalent() const; - virtual MakeInstallCommand makeInstallCommand(const Target *target, - const Utils::FilePath &installRoot); void setup(const QList &infoList); Utils::MacroExpander *macroExpander() const; diff --git a/src/plugins/projectexplorer/projectfilewizardextension.cpp b/src/plugins/projectexplorer/projectfilewizardextension.cpp index fc3fb6ec5f8..f0ba9a95710 100644 --- a/src/plugins/projectexplorer/projectfilewizardextension.cpp +++ b/src/plugins/projectexplorer/projectfilewizardextension.cpp @@ -244,7 +244,7 @@ void ProjectFileWizardExtension::applyCodeStyle(GeneratedFile *file) const if (file->isBinary() || file->contents().isEmpty()) return; // nothing to do - Id languageId = TextEditorSettings::languageId(Utils::mimeTypeForFile(file->path()).name()); + Id languageId = TextEditorSettings::languageId(Utils::mimeTypeForFile(file->filePath()).name()); if (!languageId.isValid()) return; // don't modify files like *.ui *.pro diff --git a/src/plugins/projectexplorer/projectimporter.cpp b/src/plugins/projectexplorer/projectimporter.cpp index 2db6dafa2b6..e51aaa2c968 100644 --- a/src/plugins/projectexplorer/projectimporter.cpp +++ b/src/plugins/projectexplorer/projectimporter.cpp @@ -414,9 +414,7 @@ ProjectImporter::findOrCreateToolChains(const ToolChainDescription &tcd) const { ToolChainData result; result.tcs = ToolChainManager::toolchains([&tcd](const ToolChain *tc) { - return tc->language() == tcd.language && - Utils::Environment::systemEnvironment().isSameExecutable( - tc->compilerCommand().toString(), tcd.compilerPath.toString()); + return tc->language() == tcd.language && tc->matchesCompilerCommand(tcd.compilerPath); }); for (const ToolChain *tc : qAsConst(result.tcs)) { const QByteArray tcId = tc->id(); diff --git a/src/plugins/projectexplorer/projectnodes.cpp b/src/plugins/projectexplorer/projectnodes.cpp index c4b33d74140..61dfff43d05 100644 --- a/src/plugins/projectexplorer/projectnodes.cpp +++ b/src/plugins/projectexplorer/projectnodes.cpp @@ -1094,4 +1094,28 @@ QIcon DirectoryIcon::icon() const return icon; } +ResourceFileNode::ResourceFileNode(const FilePath &filePath, const QString &qrcPath, const QString &displayName) + : FileNode(filePath, FileNode::fileTypeForFileName(filePath)) + , m_qrcPath(qrcPath) + , m_displayName(displayName) +{ +} + +QString ResourceFileNode::displayName() const +{ + return m_displayName; +} + +QString ResourceFileNode::qrcPath() const +{ + return m_qrcPath; +} + +bool ResourceFileNode::supportsAction(ProjectAction action, const Node *node) const +{ + if (action == HidePathActions) + return false; + return parentFolderNode()->supportsAction(action, node); +} + } // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectnodes.h b/src/plugins/projectexplorer/projectnodes.h index c5cd68a4c53..9e2e4e9474d 100644 --- a/src/plugins/projectexplorer/projectnodes.h +++ b/src/plugins/projectexplorer/projectnodes.h @@ -464,6 +464,20 @@ private: Project *m_project; }; +class PROJECTEXPLORER_EXPORT ResourceFileNode : public ProjectExplorer::FileNode +{ +public: + ResourceFileNode(const Utils::FilePath &filePath, const QString &qrcPath, const QString &displayName); + + QString displayName() const override; + QString qrcPath() const; + bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; + +private: + QString m_qrcPath; + QString m_displayName; +}; + } // namespace ProjectExplorer Q_DECLARE_METATYPE(ProjectExplorer::Node *) diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index bd7714546a8..b826b215698 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1257,7 +1257,6 @@ public: SimpleTargetRunner *q = nullptr; - bool m_isLocal = true; bool m_runAsRoot = false; QtcProcess m_process; @@ -1266,10 +1265,6 @@ public: QTextCodec::ConverterState m_outputCodecState; QTextCodec::ConverterState m_errorCodecState; - // Keep track whether we need to emit a finished signal - bool m_processRunning = false; - - // Remote State m_state = Inactive; bool m_stopRequested = false; @@ -1333,10 +1328,13 @@ SimpleTargetRunnerPrivate::~SimpleTargetRunnerPrivate() void SimpleTargetRunnerPrivate::stop() { m_resultData.m_exitStatus = QProcess::CrashExit; - if (m_isLocal) { + + const bool isLocal = !m_command.executable().needsDevice(); + if (isLocal) { if (!isRunning()) return; - m_process.stopProcess(); + m_process.stop(); + m_process.waitForFinished(); QTimer::singleShot(100, this, [this] { forwardDone(); }); } else { if (m_stopRequested) @@ -1345,7 +1343,8 @@ void SimpleTargetRunnerPrivate::stop() q->appendMessage(tr("User requested stop. Shutting down..."), NormalMessageFormat); switch (m_state) { case Run: - m_process.terminate(); + m_process.stop(); + m_process.waitForFinished(); break; case Inactive: break; @@ -1369,48 +1368,9 @@ qint64 SimpleTargetRunnerPrivate::privateApplicationPID() const void SimpleTargetRunnerPrivate::handleDone() { m_resultData = m_process.resultData(); + QTC_ASSERT(m_state == Run, forwardDone(); return); - if (m_isLocal) { - if (m_resultData.m_error == QProcess::UnknownError) { - forwardDone(); - return; - } - // TODO: why below handlings are different? - if (m_process.usesTerminal()) { - q->appendMessage(m_process.errorString(), ErrorMessageFormat); - if (m_processRunning && m_process.processId() == 0) { - m_processRunning = false; - m_resultData.m_exitCode = -1; // FIXME: Why? - } - } else { - QString errorString; - switch (m_resultData.m_error) { - case QProcess::FailedToStart: - errorString = tr("Failed to start program. Path or permissions wrong?"); - break; - case QProcess::Crashed: - m_resultData.m_exitStatus = QProcess::CrashExit; - break; - default: - errorString = tr("Some error has occurred while running the program."); - } - if (!errorString.isEmpty()) - q->appendMessage(errorString, ErrorMessageFormat); - if (m_processRunning && !isRunning()) { - m_processRunning = false; - m_resultData.m_exitCode = -1; - } - } - - } else { - QTC_ASSERT(m_state == Run, forwardDone(); return); - if (m_resultData.m_error == QProcess::FailedToStart) { - m_resultData.m_exitStatus = QProcess::CrashExit; - } else if (m_resultData.m_exitStatus == QProcess::CrashExit) { - m_resultData.m_error = QProcess::Crashed; - } - m_state = Inactive; - } + m_state = Inactive; forwardDone(); } @@ -1432,19 +1392,18 @@ void SimpleTargetRunnerPrivate::handleStandardError() void SimpleTargetRunnerPrivate::start() { - m_isLocal = !m_command.executable().needsDevice(); + const bool isLocal = !m_command.executable().needsDevice(); m_resultData = {}; + QTC_ASSERT(m_state == Inactive, return); - if (m_isLocal) { + if (isLocal) { Environment env = m_environment; if (m_runAsRoot) RunControl::provideAskPassEntry(env); m_process.setEnvironment(env); - m_processRunning = true; - WinDebugInterface::startIfNeeded(); CommandLine cmdLine = m_command; @@ -1457,37 +1416,27 @@ void SimpleTargetRunnerPrivate::start() m_process.setRunAsRoot(m_runAsRoot); m_process.setCommand(cmdLine); - } else { - QTC_ASSERT(m_state == Inactive, return); - - const IDevice::ConstPtr device = DeviceManager::deviceForPath(m_command.executable()); - if (!device) { - m_resultData.m_errorString = tr("Cannot run: No device."); - m_resultData.m_error = QProcess::FailedToStart; - m_resultData.m_exitStatus = QProcess::CrashExit; - forwardDone(); - return; - } - - if (!device->isEmptyCommandAllowed() && m_command.isEmpty()) { - m_resultData.m_errorString = tr("Cannot run: No command given."); - m_resultData.m_error = QProcess::FailedToStart; - m_resultData.m_exitStatus = QProcess::CrashExit; - forwardDone(); - return; - } - - m_state = Run; - m_stopRequested = false; - - m_process.setCommand(m_command); - m_process.setEnvironment(m_environment); - m_process.setExtraData(m_extraData); } + const IDevice::ConstPtr device = DeviceManager::deviceForPath(m_command.executable()); + if (device && !device->isEmptyCommandAllowed() && m_command.isEmpty()) { + m_resultData.m_errorString = tr("Cannot run: No command given."); + m_resultData.m_error = QProcess::FailedToStart; + m_resultData.m_exitStatus = QProcess::CrashExit; + forwardDone(); + return; + } + + m_stopRequested = false; + + m_process.setCommand(m_command); + m_process.setEnvironment(m_environment); + m_process.setExtraData(m_extraData); + + m_state = Run; m_process.setWorkingDirectory(m_workingDirectory); - if (m_isLocal) + if (isLocal) m_outputCodec = QTextCodec::codecForLocale(); else m_outputCodec = QTextCodec::codecForName("utf8"); diff --git a/src/plugins/projectexplorer/session.cpp b/src/plugins/projectexplorer/session.cpp index 67f1616c322..d5b3539bac2 100644 --- a/src/plugins/projectexplorer/session.cpp +++ b/src/plugins/projectexplorer/session.cpp @@ -96,8 +96,8 @@ public: QStringList dependenciesOrder() const; void dependencies(const QString &proName, QStringList &result) const; - static QString windowTitleAddition(const QString &filePath); - static QString sessionTitle(const QString &filePath); + static QString windowTitleAddition(const FilePath &filePath); + static QString sessionTitle(const FilePath &filePath); bool hasProjects() const { return !m_projects.isEmpty(); } @@ -118,7 +118,7 @@ public: PersistentSettingsWriter *m_writer = nullptr; private: - static QString locationInProject(const QString &filePath); + static QString locationInProject(const FilePath &filePath); }; static SessionManager *m_instance = nullptr; @@ -598,7 +598,7 @@ void SessionManagerPrivate::dependencies(const QString &proName, QStringList &re result.append(proName); } -QString SessionManagerPrivate::sessionTitle(const QString &filePath) +QString SessionManagerPrivate::sessionTitle(const FilePath &filePath) { if (SessionManager::isDefaultSession(d->m_sessionName)) { if (filePath.isEmpty()) { @@ -616,18 +616,17 @@ QString SessionManagerPrivate::sessionTitle(const QString &filePath) return QString(); } -QString SessionManagerPrivate::locationInProject(const QString &filePath) { - const Project *project = SessionManager::projectForFile(Utils::FilePath::fromString(filePath)); +QString SessionManagerPrivate::locationInProject(const FilePath &filePath) { + const Project *project = SessionManager::projectForFile(filePath); if (!project) return QString(); - const Utils::FilePath file = Utils::FilePath::fromString(filePath); - const Utils::FilePath parentDir = file.parentDir(); + const FilePath parentDir = filePath.parentDir(); if (parentDir == project->projectDirectory()) return "@ " + project->displayName(); - if (file.isChildOf(project->projectDirectory())) { - const Utils::FilePath dirInProject = parentDir.relativeChildPath(project->projectDirectory()); + if (filePath.isChildOf(project->projectDirectory())) { + const FilePath dirInProject = parentDir.relativeChildPath(project->projectDirectory()); return "(" + dirInProject.toUserOutput() + " @ " + project->displayName() + ")"; } @@ -637,7 +636,7 @@ QString SessionManagerPrivate::locationInProject(const QString &filePath) { return "(" + parentDir.toUserOutput() + " @ " + project->displayName() + ")"; } -QString SessionManagerPrivate::windowTitleAddition(const QString &filePath) +QString SessionManagerPrivate::windowTitleAddition(const FilePath &filePath) { return filePath.isEmpty() ? QString() : locationInProject(filePath); } diff --git a/src/plugins/projectexplorer/simpleprojectwizard.cpp b/src/plugins/projectexplorer/simpleprojectwizard.cpp index 6d7b2e2884f..0b8a20a29ff 100644 --- a/src/plugins/projectexplorer/simpleprojectwizard.cpp +++ b/src/plugins/projectexplorer/simpleprojectwizard.cpp @@ -224,7 +224,7 @@ GeneratedFiles generateQmakeFiles(const SimpleProjectWizardDialog *wizard, for (const FilePath &fileName : wizard->selectedFiles()) { QString source = dir.relativeFilePath(fileName.toString()); - MimeType mimeType = Utils::mimeTypeForFile(fileName.toFileInfo()); + MimeType mimeType = Utils::mimeTypeForFile(fileName); if (mimeType.matchesName("text/x-chdr") || mimeType.matchesName("text/x-c++hdr")) proHeaders += " $$PWD/" + source + " \\\n"; else diff --git a/src/plugins/projectexplorer/target.cpp b/src/plugins/projectexplorer/target.cpp index 76de5d0da66..964461bfb5a 100644 --- a/src/plugins/projectexplorer/target.cpp +++ b/src/plugins/projectexplorer/target.cpp @@ -803,11 +803,6 @@ QVariant Target::additionalData(Utils::Id id) const return {}; } -MakeInstallCommand Target::makeInstallCommand(const FilePath &installRoot) const -{ - return project()->makeInstallCommand(this, installRoot); -} - MacroExpander *Target::macroExpander() const { return &d->m_macroExpander; diff --git a/src/plugins/projectexplorer/target.h b/src/plugins/projectexplorer/target.h index a5503ff833b..b1ff67c2d2f 100644 --- a/src/plugins/projectexplorer/target.h +++ b/src/plugins/projectexplorer/target.h @@ -25,9 +25,12 @@ #pragma once -#include "projectconfiguration.h" #include "projectexplorer_export.h" +#include + +#include + #include QT_FORWARD_DECLARE_CLASS(QIcon) @@ -41,7 +44,6 @@ class BuildSystem; class DeployConfiguration; class DeploymentData; class Kit; -class MakeInstallCommand; class Project; class ProjectConfigurationModel; class RunConfiguration; @@ -114,7 +116,6 @@ public: void setNamedSettings(const QString &name, const QVariant &value); QVariant additionalData(Utils::Id id) const; - MakeInstallCommand makeInstallCommand(const Utils::FilePath &installRoot) const; Utils::MacroExpander *macroExpander() const; diff --git a/src/plugins/projectexplorer/taskhub.cpp b/src/plugins/projectexplorer/taskhub.cpp index ec402ad03bf..02d1f713e60 100644 --- a/src/plugins/projectexplorer/taskhub.cpp +++ b/src/plugins/projectexplorer/taskhub.cpp @@ -153,11 +153,18 @@ void TaskHub::addTask(Task::TaskType type, const QString &description, Utils::Id void TaskHub::addTask(Task task) { + if (QThread::currentThread() != qApp->thread()) { + QMetaObject::invokeMethod(qApp, [&task] { + TaskHub::addTask(task); + }); + + return; + } + QTC_ASSERT(m_registeredCategories.contains(task.category), return); QTC_ASSERT(!task.description().isEmpty(), return); QTC_ASSERT(!task.isNull(), return); QTC_ASSERT(task.m_mark.isNull(), return); - QTC_ASSERT(QThread::currentThread() == qApp->thread(), return); if (task.file.isEmpty() || task.line <= 0) task.line = -1; diff --git a/src/plugins/projectexplorer/toolchain.cpp b/src/plugins/projectexplorer/toolchain.cpp index f36ce9414b6..32d39fc0806 100644 --- a/src/plugins/projectexplorer/toolchain.cpp +++ b/src/plugins/projectexplorer/toolchain.cpp @@ -343,6 +343,11 @@ void ToolChain::setCompilerCommand(const FilePath &command) toolChainUpdated(); } +bool ToolChain::matchesCompilerCommand(const Utils::FilePath &command, const Environment &env) const +{ + return env.isSameExecutable(compilerCommand().toString(), command.toString()); +} + void ToolChain::setCompilerCommandKey(const QString &commandKey) { d->m_compilerCommandKey = commandKey; diff --git a/src/plugins/projectexplorer/toolchain.h b/src/plugins/projectexplorer/toolchain.h index 2e41313f2ec..6a3ced00535 100644 --- a/src/plugins/projectexplorer/toolchain.h +++ b/src/plugins/projectexplorer/toolchain.h @@ -156,6 +156,9 @@ public: virtual Utils::FilePath compilerCommand() const; // FIXME: De-virtualize. void setCompilerCommand(const Utils::FilePath &command); + virtual bool matchesCompilerCommand( + const Utils::FilePath &command, + const Utils::Environment &env = Utils::Environment::systemEnvironment()) const; virtual QList createOutputParsers() const = 0; diff --git a/src/plugins/projectexplorer/toolchainoptionspage.cpp b/src/plugins/projectexplorer/toolchainoptionspage.cpp index 7f0c17a5c63..b8dccb01998 100644 --- a/src/plugins/projectexplorer/toolchainoptionspage.cpp +++ b/src/plugins/projectexplorer/toolchainoptionspage.cpp @@ -363,27 +363,24 @@ ToolChainTreeItem *ToolChainOptionsWidget::insertToolChain(ToolChain *tc, bool c void ToolChainOptionsWidget::addToolChain(ToolChain *tc) { - for (int i = 0; i < m_toAddList.size(); ++i) { - if (m_toAddList.at(i)->toolChain == tc) { - // do not delete i element: Still used elsewhere! - m_toAddList.removeAt(i); - return; - } + if (Utils::eraseOne(m_toAddList, [tc](const ToolChainTreeItem *item) { + return item->toolChain == tc; })) { + // do not delete here! + return; } insertToolChain(tc); - updateState(); } void ToolChainOptionsWidget::removeToolChain(ToolChain *tc) { - for (int i = 0; i < m_toRemoveList.size(); ++i) { - if (m_toRemoveList.at(i)->toolChain == tc) { - m_toRemoveList.removeAt(i); - delete m_toRemoveList.at(i); - return; - } + if (auto it = std::find_if(m_toRemoveList.begin(), m_toRemoveList.end(), + [tc](const ToolChainTreeItem *item) { return item->toolChain == tc; }); + it != m_toRemoveList.end()) { + m_toRemoveList.erase(it); + delete *it; + return; } StaticTreeItem *parent = parentForToolChain(tc); diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index c354ebb4e14..44ee82727c0 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -95,7 +95,8 @@ void PipInstallTask::run() void PipInstallTask::cancel() { - m_process.stopProcess(); + m_process.stop(); + m_process.waitForFinished(); Core::MessageManager::writeFlashing( tr("The %1 installation was canceled by %2.") .arg(m_package.displayName, m_killTimer.isActive() ? tr("user") : tr("time out"))); diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index fc8a367da45..a04d2b723a7 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -198,6 +198,10 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id) connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); connect(target, &Target::buildSystemUpdated, this, &PythonRunConfiguration::updateExtraCompilers); currentInterpreterChanged(); + + setRunnableModifier([](Runnable &r) { + r.workingDirectory = r.workingDirectory.onDevice(r.command.executable()); + }); } PythonRunConfiguration::~PythonRunConfiguration() diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index ae4fd3a1f77..08c8750c21f 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -47,36 +47,42 @@ namespace Internal { FilePath detectPython(const FilePath &documentPath) { - FilePath python; - - PythonProject *project = documentPath.isEmpty() - ? nullptr - : qobject_cast( - SessionManager::projectForFile(documentPath)); + Project *project = documentPath.isEmpty() ? nullptr + : SessionManager::projectForFile(documentPath); if (!project) - project = qobject_cast(SessionManager::startupProject()); + project = SessionManager::startupProject(); + + Environment env = Environment::systemEnvironment(); if (project) { if (auto target = project->activeTarget()) { if (auto runConfig = target->activeRunConfiguration()) { if (auto interpreter = runConfig->aspect()) - python = interpreter->currentInterpreter().command; + return interpreter->currentInterpreter().command; + if (auto environmentAspect = runConfig->aspect()) + env = environmentAspect->environment(); } } } // check whether this file is inside a python virtual environment - QList venvInterpreters = PythonSettings::detectPythonVenvs(documentPath); - if (!python.exists() && !venvInterpreters.isEmpty()) - python = venvInterpreters.first().command; + const QList venvInterpreters = PythonSettings::detectPythonVenvs(documentPath); + if (!venvInterpreters.isEmpty()) + return venvInterpreters.first().command; - if (!python.exists()) - python = PythonSettings::defaultInterpreter().command; + auto defaultInterpreter = PythonSettings::defaultInterpreter().command; + if (defaultInterpreter.exists()) + return defaultInterpreter; - if (!python.exists() && !PythonSettings::interpreters().isEmpty()) - python = PythonSettings::interpreters().constFirst().command; + const FilePath python3FromPath = env.searchInPath("python3"); + if (python3FromPath.exists()) + return python3FromPath; - return python; + const FilePath pythonFromPath = env.searchInPath("python"); + if (pythonFromPath.exists()) + return pythonFromPath; + + return PythonSettings::interpreters().value(0).command; } static QStringList replImportArgs(const FilePath &pythonFile, ReplType type) diff --git a/src/plugins/qbsprojectmanager/qbssession.cpp b/src/plugins/qbsprojectmanager/qbssession.cpp index 76bf4e14c00..bd2c3ecb496 100644 --- a/src/plugins/qbsprojectmanager/qbssession.cpp +++ b/src/plugins/qbsprojectmanager/qbssession.cpp @@ -182,23 +182,12 @@ void QbsSession::initialize() connect(d->qbsProcess, &QtcProcess::readyReadStandardError, this, [this] { qCDebug(qbsPmLog) << "[qbs stderr]: " << d->qbsProcess->readAllStandardError(); }); - connect(d->qbsProcess, &QtcProcess::errorOccurred, this, [this](QProcess::ProcessError e) { - d->eventLoop.exit(1); - switch (e) { - case QProcess::FailedToStart: + connect(d->qbsProcess, &QtcProcess::done, this, [this] { + if (d->qbsProcess->result() == ProcessResult::StartFailed) { + d->eventLoop.exit(1); setError(Error::QbsFailedToStart); - break; - case QProcess::WriteError: - case QProcess::ReadError: - setError(Error::ProtocolError); - break; - case QProcess::Crashed: - case QProcess::Timedout: - case QProcess::UnknownError: - break; + return; } - }); - connect(d->qbsProcess, &QtcProcess::finished, this, [this] { d->qbsProcess->deleteLater(); switch (d->state) { case State::Inactive: diff --git a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp index 8ae6a7cf1e5..10fc625d562 100644 --- a/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp +++ b/src/plugins/qmakeprojectmanager/qmakenodetreebuilder.cpp @@ -179,7 +179,8 @@ static void createTree(QmakeBuildSystem *buildSystem, vfolder->setIcon(fileTypes.at(i).icon); vfolder->setDisplayName(fileTypes.at(i).typeName); vfolder->setAddFileFilter(fileTypes.at(i).addFileFilter); - vfolder->setIsSourcesOrHeaders(type == FileType::Source || type == FileType::Header); + vfolder->setIsSourcesOrHeaders(type == FileType::Source || type == FileType::Header + || type == FileType::Form); if (type == FileType::Resource) { for (const auto &file : newFilePaths) { diff --git a/src/plugins/qmakeprojectmanager/qmakeproject.cpp b/src/plugins/qmakeprojectmanager/qmakeproject.cpp index c77f468ae23..bff8df79024 100644 --- a/src/plugins/qmakeprojectmanager/qmakeproject.cpp +++ b/src/plugins/qmakeprojectmanager/qmakeproject.cpp @@ -1390,7 +1390,7 @@ void QmakeBuildSystem::testToolChain(ToolChain *tc, const FilePath &path) const const Utils::FilePath expected = tc->compilerCommand(); Environment env = buildConfiguration()->environment(); - if (env.isSameExecutable(path.toString(), expected.toString())) + if (tc->matchesCompilerCommand(expected, env)) return; const QPair pair = qMakePair(expected, path); if (m_toolChainWarnings.contains(pair)) diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.qbs b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.qbs index 031b0977bc5..a8bc03685f3 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.qbs +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.qbs @@ -2,13 +2,14 @@ import qbs QtcProduct { name: "assetexporterplugin" + condition: QmlDesigner.present type: ["dynamiclibrary"] installDir: qtc.ide_plugin_path + '/' + installDirName property string installDirName: qbs.targetOS.contains("macos") ? "QmlDesigner" : "qmldesigner" Depends { name: "Core" } Depends { name: "ProjectExplorer" } - Depends { name: "QmlDesigner" } + Depends { name: "QmlDesigner"; required: false } Depends { name: "Utils" } Depends { name: "Qt" diff --git a/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs b/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs index 84adc2b5304..520e533af5b 100644 --- a/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs +++ b/src/plugins/qmldesigner/componentsplugin/componentsplugin.qbs @@ -2,12 +2,13 @@ import qbs QtcProduct { name: "componentsplugin" + condition: QmlDesigner.present type: ["dynamiclibrary"] installDir: qtc.ide_plugin_path + '/' + installDirName property string installDirName: qbs.targetOS.contains("macos") ? "QmlDesigner" : "qmldesigner" Depends { name: "Core" } - Depends { name: "QmlDesigner" } + Depends { name: "QmlDesigner"; required: false } Depends { name: "Utils" } Depends { name: "Qt.qml" } diff --git a/src/plugins/qmldesigner/generateresource.cpp b/src/plugins/qmldesigner/generateresource.cpp index 7210a144717..b85370f60f9 100644 --- a/src/plugins/qmldesigner/generateresource.cpp +++ b/src/plugins/qmldesigner/generateresource.cpp @@ -255,7 +255,6 @@ void GenerateResource::generateMenuEntry() QByteArray stdOut; QByteArray stdErr; if (!rccProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) { - rccProcess.stopProcess(); Core::MessageManager::writeDisrupting( QCoreApplication::translate("QmlDesigner::GenerateResource", "A timeout occurred running \"%1\"") @@ -415,7 +414,6 @@ void GenerateResource::generateMenuEntry() QByteArray stdOut; QByteArray stdErr; if (!rccProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) { - rccProcess.stopProcess(); Core::MessageManager::writeDisrupting( QCoreApplication::translate("QmlDesigner::GenerateResource", "A timeout occurred running \"%1\"") @@ -545,7 +543,6 @@ void GenerateResource::generateMenuEntry() QByteArray stdOut; QByteArray stdErr; if (!rccProcess.readDataFromProcess(30, &stdOut, &stdErr, true)) { - rccProcess.stopProcess(); Core::MessageManager::writeDisrupting( QCoreApplication::translate("QmlDesigner::GenerateResource", "A timeout occurred running \"%1\"") diff --git a/src/plugins/qmldesigner/qmldesignercore.cmake b/src/plugins/qmldesigner/qmldesignercore.cmake index b904057da2b..46e30173a3b 100644 --- a/src/plugins/qmldesigner/qmldesignercore.cmake +++ b/src/plugins/qmldesigner/qmldesignercore.cmake @@ -49,6 +49,21 @@ function(extend_with_qmldesigner_core target_name) rewritertransaction.h ) + # autouic gets confused when adding the ui files to tests in the qtquickdesigner repo, + # so manually add them for UIC + set(UI_FILES + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/designercore/instances/puppetbuildprogressdialog.ui + ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/designercore/instances/puppetdialog.ui + ) + qt_wrap_ui(UI_SOURCES ${UI_FILES}) + extend_qtc_target(${target_name} + INCLUDES ${CMAKE_CURRENT_BINARY_DIR} + SOURCES + ${UI_SOURCES} + ${UI_FILES} + ) + set_source_files_properties(${UI_FILES} PROPERTIES SKIP_AUTOUIC ON) + extend_qtc_target(${target_name} INCLUDES ${CMAKE_CURRENT_FUNCTION_LIST_DIR}/designercore/exceptions @@ -204,12 +219,10 @@ function(extend_with_qmldesigner_core target_name) instances/nodeinstanceview.cpp instances/puppetbuildprogressdialog.cpp instances/puppetbuildprogressdialog.h - instances/puppetbuildprogressdialog.ui instances/puppetcreator.cpp instances/puppetcreator.h instances/puppetdialog.cpp instances/puppetdialog.h - instances/puppetdialog.ui instances/qprocessuniqueptr.h metainfo/itemlibraryinfo.cpp diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index 0ea3b5008a1..7b8ef977751 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -5,13 +5,12 @@ Project { name: "QmlDesigner" QtcPlugin { + condition: Qt.quickwidgets.present && Qt.svg.present fileName: FileInfo.fileName(filePath) Depends { - name: "Qt"; - submodules: [ - "core-private", "quickwidgets", "xml", "svg" - ] + name: "Qt"; versionAtLeast: "6.2"; required: false + submodules: ["core-private", "quickwidgets", "xml", "svg"] } Depends { name: "AdvancedDockingSystem" } Depends { name: "Core" } diff --git a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.qbs b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.qbs index 8e48e6aa850..05e809d4331 100644 --- a/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.qbs +++ b/src/plugins/qmldesigner/qmlpreviewplugin/qmlpreviewplugin.qbs @@ -2,6 +2,7 @@ import qbs QtcProduct { name: "qmlpreviewplugin" + condition: QmlDesigner.present type: ["dynamiclibrary"] installDir: qtc.ide_plugin_path + '/' + installDirName property string installDirName: qbs.targetOS.contains("macos") ? "QmlDesigner" : "qmldesigner" @@ -15,7 +16,7 @@ QtcProduct { Depends { name: "Core" } Depends { name: "ProjectExplorer" } - Depends { name: "QmlDesigner" } + Depends { name: "QmlDesigner"; required: false } Depends { name: "Qt.qml" } Depends { name: "Utils" } diff --git a/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp b/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp index aebce83d5a9..f4c6e438072 100644 --- a/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp +++ b/src/plugins/qmlpreview/qmlpreviewfileontargetfinder.cpp @@ -33,8 +33,6 @@ #include #include -#include - #include namespace QmlPreview { @@ -52,7 +50,7 @@ ProjectExplorer::Target *QmlPreviewFileOnTargetFinder::target() const QString resourceNodePath(const ProjectExplorer::Node *node) { - if (auto resourceNode = dynamic_cast(node)) + if (auto resourceNode = dynamic_cast(node)) return ":" + resourceNode->qrcPath(); return QString(); } diff --git a/src/plugins/qmlprojectmanager/qdslandingpage.cpp b/src/plugins/qmlprojectmanager/qdslandingpage.cpp index 6ca001ae7fc..13b469a18e7 100644 --- a/src/plugins/qmlprojectmanager/qdslandingpage.cpp +++ b/src/plugins/qmlprojectmanager/qdslandingpage.cpp @@ -103,12 +103,14 @@ QWidget *QdsLandingPage::widget() void QdsLandingPage::show() { - m_widget->rootObject()->setProperty(PROPERTY_QDSINSTALLED, m_qdsInstalled); - m_widget->rootObject()->setProperty(PROPERTY_PROJECTFILEEXISTS, m_projectFileExists); - m_widget->rootObject()->setProperty(PROPERTY_QTVERSION, m_qtVersion); - m_widget->rootObject()->setProperty(PROPERTY_QDSVERSION, m_qdsVersion); - m_widget->rootObject()->setProperty(PROPERTY_CMAKES, m_cmakeResources); - m_widget->rootObject()->setProperty(PROPERTY_REMEMBER, Qt::Unchecked); + if (m_widget->rootObject()) { + m_widget->rootObject()->setProperty(PROPERTY_QDSINSTALLED, m_qdsInstalled); + m_widget->rootObject()->setProperty(PROPERTY_PROJECTFILEEXISTS, m_projectFileExists); + m_widget->rootObject()->setProperty(PROPERTY_QTVERSION, m_qtVersion); + m_widget->rootObject()->setProperty(PROPERTY_QDSVERSION, m_qdsVersion); + m_widget->rootObject()->setProperty(PROPERTY_CMAKES, m_cmakeResources); + m_widget->rootObject()->setProperty(PROPERTY_REMEMBER, Qt::Unchecked); + } m_widget->show(); } diff --git a/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp b/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp index d16f79ed64f..404b43bb772 100644 --- a/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp +++ b/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp @@ -27,7 +27,6 @@ #include "qmlproject.h" #include "qmlprojectmanagerconstants.h" -#include "qmlprojectrunconfiguration.h" #include @@ -75,7 +74,7 @@ QmlMainFileAspect::~QmlMainFileAspect() delete m_fileListCombo; } -void QmlMainFileAspect::addToLayout(Utils::LayoutBuilder &builder) +void QmlMainFileAspect::addToLayout(LayoutBuilder &builder) { QTC_ASSERT(!m_fileListCombo, delete m_fileListCombo); m_fileListCombo = new QComboBox; @@ -238,7 +237,7 @@ bool QmlMainFileAspect::isQmlFilePresent() bool qmlFileFound = false; if (mainScriptSource() == FileInEditor) { IDocument *document = EditorManager::currentDocument(); - Utils::MimeType mainScriptMimeType = Utils::mimeTypeForFile(mainScript()); + const MimeType mainScriptMimeType = mimeTypeForFile(mainScript()); if (document) { m_currentFileFilename = document->filePath().toString(); if (mainScriptMimeType.matchesName(ProjectExplorer::Constants::QML_MIMETYPE) @@ -251,11 +250,9 @@ bool QmlMainFileAspect::isQmlFilePresent() // find a qml file with lowercase filename. This is slow, but only done // in initialization/other border cases. const auto files = m_target->project()->files(Project::SourceFiles); - for (const Utils::FilePath &filename : files) { - const QFileInfo fi = filename.toFileInfo(); - - if (!filename.isEmpty() && fi.baseName().at(0).isLower()) { - Utils::MimeType type = Utils::mimeTypeForFile(fi); + for (const FilePath &filename : files) { + if (!filename.isEmpty() && filename.baseName().at(0).isLower()) { + const MimeType type = mimeTypeForFile(filename); if (type.matchesName(ProjectExplorer::Constants::QML_MIMETYPE) || type.matchesName(ProjectExplorer::Constants::QMLUI_MIMETYPE)) { m_currentFileFilename = filename.toString(); diff --git a/src/plugins/qnx/qnxplugin.cpp b/src/plugins/qnx/qnxplugin.cpp index b939efeae77..f5cf7991ec6 100644 --- a/src/plugins/qnx/qnxplugin.cpp +++ b/src/plugins/qnx/qnxplugin.cpp @@ -54,7 +54,6 @@ #include #include -#include #include #include #include @@ -105,7 +104,6 @@ public: && prj->hasMakeInstallEquivalent(); }); addInitialStep(DeviceCheckBuildStep::stepId()); - addInitialStep(RemoteLinux::Constants::CheckForFreeDiskSpaceId); addInitialStep(QnxUploadStep::stepId()); } }; @@ -123,7 +121,6 @@ public: QnxDeviceFactory deviceFactory; QnxDeployConfigurationFactory deployConfigFactory; GenericQnxDeployStepFactory directUploadDeployFactory; - GenericQnxDeployStepFactory checkForFreeDiskSpaceDeployFactory; GenericQnxDeployStepFactory makeInstallDeployFactory; GenericQnxDeployStepFactory checkBuildDeployFactory; QnxRunConfigurationFactory runConfigFactory; diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp index 6639f772059..e46b5cec8e0 100644 --- a/src/plugins/qnx/qnxutils.cpp +++ b/src/plugins/qnx/qnxutils.cpp @@ -118,10 +118,8 @@ EnvironmentItems QnxUtils::qnxEnvironmentFromEnvFile(const FilePath &filePath) QApplication::setOverrideCursor(Qt::BusyCursor); bool waitResult = process.waitForFinished(10000); QApplication::restoreOverrideCursor(); - if (!waitResult) { - process.stopProcess(); + if (!waitResult) return items; - } if (process.result() != ProcessResult::FinishedWithSuccess) return items; diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 62b2927b022..4298c74590e 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -157,6 +157,10 @@ static QSet versionedIds(const QByteArray &prefix, int major, int minor) result.insert(Id::fromName(featureDotMajor + '.' + minorStr)); } + // FIXME: Terrible hack. Get rid of using version numbers as tags! + if (major > 5) + result.unite(versionedIds(prefix, major - 1, 15)); + return result; } @@ -1693,7 +1697,7 @@ void QtVersion::populateQmlFileFinder(FileInProjectFinder *finder, const Target if (startupProject) { if (ProjectNode *rootNode = startupProject->rootProjectNode()) { rootNode->forEachNode([&](FileNode *node) { - if (auto resourceNode = dynamic_cast(node)) + if (auto resourceNode = dynamic_cast(node)) finder->addMappedPath(node->filePath(), ":" + resourceNode->qrcPath()); }); } else { @@ -1805,7 +1809,6 @@ static QByteArray runQmakeQuery(const FilePath &binary, const Environment &env, return {}; } if (!process.waitForFinished(timeOutMS)) { - process.stopProcess(); *error = QCoreApplication::translate("QtVersion", "Timeout running \"%1\" (%2 ms).") .arg(binary.displayName()).arg(timeOutMS); return {}; diff --git a/src/plugins/remotelinux/CMakeLists.txt b/src/plugins/remotelinux/CMakeLists.txt index 2de46781890..a13af8cd47b 100644 --- a/src/plugins/remotelinux/CMakeLists.txt +++ b/src/plugins/remotelinux/CMakeLists.txt @@ -4,7 +4,6 @@ add_qtc_plugin(RemoteLinux SOURCES abstractremotelinuxdeployservice.cpp abstractremotelinuxdeployservice.h abstractremotelinuxdeploystep.cpp abstractremotelinuxdeploystep.h - checkforfreediskspacestep.cpp checkforfreediskspacestep.h customcommanddeploystep.cpp customcommanddeploystep.h deploymenttimeinfo.cpp deploymenttimeinfo.h genericdirectuploadservice.cpp genericdirectuploadservice.h diff --git a/src/plugins/remotelinux/checkforfreediskspacestep.cpp b/src/plugins/remotelinux/checkforfreediskspacestep.cpp deleted file mode 100644 index 3c2cb42c27b..00000000000 --- a/src/plugins/remotelinux/checkforfreediskspacestep.cpp +++ /dev/null @@ -1,153 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "checkforfreediskspacestep.h" - -#include "abstractremotelinuxdeployservice.h" - -#include - -#include -#include - -#include - -#include - -using namespace ProjectExplorer; -using namespace Utils; - -namespace RemoteLinux { - -class CheckForFreeDiskSpaceService : public AbstractRemoteLinuxDeployService -{ - Q_DECLARE_TR_FUNCTIONS(RemoteLinux::CheckForFreeDiskSpaceService) - -public: - CheckForFreeDiskSpaceService() {} - - void setPathToCheck(const QString &path); - void setRequiredSpaceInBytes(quint64 sizeInBytes); - -private: - bool isDeploymentNecessary() const override { return true; } - - CheckResult isDeploymentPossible() const override; - - void doDeploy() final; - void stopDeployment() final {} - - QString m_pathToCheck; - quint64 m_requiredSpaceInBytes = 0; -}; - -void CheckForFreeDiskSpaceService::setPathToCheck(const QString &path) -{ - m_pathToCheck = path; -} - -void CheckForFreeDiskSpaceService::setRequiredSpaceInBytes(quint64 sizeInBytes) -{ - m_requiredSpaceInBytes = sizeInBytes; -} - -void CheckForFreeDiskSpaceService::doDeploy() -{ - auto cleanup = qScopeGuard([this] { setFinished(); }); - const FilePath path = deviceConfiguration()->filePath(m_pathToCheck); - const qint64 freeSpace = path.bytesAvailable(); - if (freeSpace < 0) { - emit errorMessage(tr("Cannot get info about free disk space for \"%1\"") - .arg(path.displayName())); - handleDeploymentDone(); - return; - } - - const qint64 mb = 1024 * 1024; - const qint64 freeSpaceMB = freeSpace / mb; - const qint64 requiredSpaceMB = m_requiredSpaceInBytes / mb; - - if (freeSpaceMB < requiredSpaceMB) { - emit errorMessage(tr("The remote file system has only %n megabytes of free space, " - "but %1 megabytes are required.", nullptr, freeSpaceMB) - .arg(requiredSpaceMB)); - handleDeploymentDone(); - return; - } - - emit progressMessage(tr("The remote file system has %n megabytes of free space, going ahead.", - nullptr, freeSpaceMB)); - handleDeploymentDone(); -} - -CheckResult CheckForFreeDiskSpaceService::isDeploymentPossible() const -{ - if (!m_pathToCheck.startsWith('/')) { - return CheckResult::failure( - tr("Cannot check for free disk space: \"%1\" is not an absolute path.") - .arg(m_pathToCheck)); - } - - return AbstractRemoteLinuxDeployService::isDeploymentPossible(); -} - -CheckForFreeDiskSpaceStep::CheckForFreeDiskSpaceStep - (BuildStepList *bsl, Id id) - : AbstractRemoteLinuxDeployStep(bsl, id) -{ - auto service = createDeployService(); - - auto pathToCheckAspect = addAspect(); - pathToCheckAspect->setSettingsKey("RemoteLinux.CheckForFreeDiskSpaceStep.PathToCheck"); - pathToCheckAspect->setDisplayStyle(StringAspect::LineEditDisplay); - pathToCheckAspect->setValue("/"); - pathToCheckAspect->setLabelText(tr("Remote path to check for free space:")); - - auto requiredSpaceAspect = addAspect(); - requiredSpaceAspect->setSettingsKey("RemoteLinux.CheckForFreeDiskSpaceStep.RequiredSpace"); - requiredSpaceAspect->setLabel(tr("Required disk space:")); - requiredSpaceAspect->setDisplayScaleFactor(1024*1024); - requiredSpaceAspect->setValue(5*1024*1024); - requiredSpaceAspect->setSuffix(tr("MB")); - requiredSpaceAspect->setRange(1, std::numeric_limits::max()); - - setInternalInitializer([service, pathToCheckAspect, requiredSpaceAspect] { - service->setPathToCheck(pathToCheckAspect->value()); - service->setRequiredSpaceInBytes(requiredSpaceAspect->value()); - return CheckResult::success(); - }); -} - -Id CheckForFreeDiskSpaceStep::stepId() -{ - return "RemoteLinux.CheckForFreeDiskSpaceStep"; -} - -QString CheckForFreeDiskSpaceStep::displayName() -{ - return tr("Check for free disk space"); -} - -} // namespace RemoteLinux diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 55be3fe0575..edc6a624562 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -497,27 +497,6 @@ qint64 SshProcessInterface::write(const QByteArray &data) return d->m_process.writeRaw(data); } -bool SshProcessInterface::waitForStarted(int msecs) -{ - Q_UNUSED(msecs) - QTC_CHECK(false); - return false; -} - -bool SshProcessInterface::waitForReadyRead(int msecs) -{ - Q_UNUSED(msecs) - QTC_CHECK(false); - return false; -} - -bool SshProcessInterface::waitForFinished(int msecs) -{ - Q_UNUSED(msecs) - QTC_CHECK(false); - return false; -} - LinuxProcessInterface::LinuxProcessInterface(const LinuxDevice *linuxDevice) : SshProcessInterface(linuxDevice) { @@ -1125,20 +1104,6 @@ QString LinuxDevice::userAtHost() const return sshParameters().userAtHost(); } -FilePath LinuxDevice::mapToGlobalPath(const FilePath &pathOnDevice) const -{ - if (pathOnDevice.needsDevice()) { - // Already correct form, only sanity check it's ours... - QTC_CHECK(handlesFile(pathOnDevice)); - return pathOnDevice; - } - FilePath result; - result.setScheme("device"); - result.setHost(id().toString()); - result.setPath(pathOnDevice.path()); - return result; -} - bool LinuxDevice::handlesFile(const FilePath &filePath) const { if (filePath.scheme() == "device" && filePath.host() == id().toString()) diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index 1b286ac1080..2e7000a09dd 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -56,7 +56,6 @@ public: ProjectExplorer::DeviceEnvironmentFetcher::Ptr environmentFetcher() const override; QString userAtHost() const; - Utils::FilePath mapToGlobalPath(const Utils::FilePath &pathOnDevice) const override; bool handlesFile(const Utils::FilePath &filePath) const override; bool isExecutableFile(const Utils::FilePath &filePath) const override; diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 4c7ac4302b5..796b9c87d4e 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -42,7 +42,13 @@ namespace RemoteLinux { namespace Internal { namespace { -enum State { Inactive, TestingEcho, TestingUname, TestingPorts, TestingSftp, TestingRsync }; +enum State { Inactive, + TestingEcho, + TestingUname, + TestingPorts, + TestingSftp, + TestingRsync, + TestingCommands }; } // anonymous namespace @@ -56,8 +62,43 @@ public: FileTransfer fileTransfer; State state = Inactive; bool sftpWorks = false; + int currentCommandIndex = 0; + bool commandFailed = false; + QtcProcess commandsProcess; }; +const QStringList s_commandsToTest = {"base64", + "cat", + "chmod", + "cp", + "cut", + "dd", + "df", + "echo", + "eval", + "exit", + "kill", + "ls", + "mkdir", + "mkfifo", + "mktemp", + "mv", + "printf", + "read", + "readlink", + "rm", + "sed", + "sh", + "shift", + "stat", + "tail", + "test", + "trap", + "touch", + "which"}; +// other possible commands (checked for qnx): +// "awk", "grep", "netstat", "print", "pidin", "sleep", "uname" + } // namespace Internal using namespace Internal; @@ -75,6 +116,8 @@ GenericLinuxDeviceTester::GenericLinuxDeviceTester(QObject *parent) this, &GenericLinuxDeviceTester::handlePortsGathererDone); connect(&d->fileTransfer, &FileTransfer::done, this, &GenericLinuxDeviceTester::handleFileTransferDone); + connect(&d->commandsProcess, &QtcProcess::done, + this, &GenericLinuxDeviceTester::handleCommandDone); } GenericLinuxDeviceTester::~GenericLinuxDeviceTester() = default; @@ -106,6 +149,9 @@ void GenericLinuxDeviceTester::stopTest() case TestingRsync: d->fileTransfer.stop(); break; + case TestingCommands: + d->commandsProcess.close(); + break; case Inactive: break; } @@ -134,14 +180,15 @@ void GenericLinuxDeviceTester::handleEchoDone() else emit errorMessage(tr("echo failed.") + '\n'); setFinished(TestFailure); - } else { - const QString reply = d->echoProcess.stdOut().chopped(1); // Remove trailing \n - if (reply != s_echoContents) - emit errorMessage(tr("Device replied to echo with unexpected contents.") + '\n'); - else - emit progressMessage(tr("Device replied to echo with expected contents.") + '\n'); + return; } + const QString reply = d->echoProcess.stdOut().chopped(1); // Remove trailing \n + if (reply != s_echoContents) + emit errorMessage(tr("Device replied to echo with unexpected contents.") + '\n'); + else + emit progressMessage(tr("Device replied to echo with expected contents.") + '\n'); + testUname(); } @@ -253,10 +300,59 @@ void GenericLinuxDeviceTester::handleFileTransferDone(const ProcessResultData &r } } d->device->setExtraData(Constants::SupportsRSync, succeeded); - setFinished(d->sftpWorks || succeeded ? TestSuccess : TestFailure); + if (d->sftpWorks || succeeded) + testCommands(); + else + setFinished(TestFailure); } } +void GenericLinuxDeviceTester::testCommands() +{ + d->state = TestingCommands; + emit progressMessage(tr("Checking if required commands are available...")); + + d->currentCommandIndex = 0; + d->commandFailed = false; + testNextCommand(); +} + +void GenericLinuxDeviceTester::testNextCommand() +{ + d->commandsProcess.close(); + if (s_commandsToTest.size() == d->currentCommandIndex) { + setFinished(d->commandFailed ? TestFailure : TestSuccess); + return; + } + + const QString commandName = s_commandsToTest[d->currentCommandIndex]; + emit progressMessage(tr("%1...").arg(commandName)); + CommandLine command{d->device->filePath("/bin/sh"), {"-c"}}; + command.addArgs(QLatin1String("\"command -v %1\"").arg(commandName), CommandLine::Raw); + d->commandsProcess.setCommand(command); + d->commandsProcess.start(); +} + +void GenericLinuxDeviceTester::handleCommandDone() +{ + QTC_ASSERT(d->state == TestingCommands, return); + + const QString command = s_commandsToTest[d->currentCommandIndex]; + if (d->commandsProcess.result() == ProcessResult::FinishedWithSuccess) { + emit progressMessage(tr("%1 found.").arg(command)); + } else { + d->commandFailed = true; + const QString message = d->commandsProcess.result() == ProcessResult::StartFailed + ? tr("An error occurred while checking for %1.").arg(command) + + '\n' + d->commandsProcess.errorString() + : tr("%1 not found.").arg(command); + emit errorMessage(message); + } + + ++d->currentCommandIndex; + testNextCommand(); +} + void GenericLinuxDeviceTester::setFinished(TestResult result) { d->state = Inactive; diff --git a/src/plugins/remotelinux/linuxdevicetester.h b/src/plugins/remotelinux/linuxdevicetester.h index 890484a8705..67c392771a6 100644 --- a/src/plugins/remotelinux/linuxdevicetester.h +++ b/src/plugins/remotelinux/linuxdevicetester.h @@ -61,6 +61,10 @@ private: void testFileTransfer(ProjectExplorer::FileTransferMethod method); void handleFileTransferDone(const Utils::ProcessResultData &resultData); + void testCommands(); + void testNextCommand(); + void handleCommandDone(); + void setFinished(ProjectExplorer::DeviceTester::TestResult result); std::unique_ptr d; diff --git a/src/plugins/remotelinux/makeinstallstep.cpp b/src/plugins/remotelinux/makeinstallstep.cpp index c61df08f6cc..f5f60b95bfc 100644 --- a/src/plugins/remotelinux/makeinstallstep.cpp +++ b/src/plugins/remotelinux/makeinstallstep.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include #include @@ -67,6 +69,18 @@ MakeInstallStep::MakeInstallStep(BuildStepList *parent, Id id) : MakeStep(parent jobCountAspect()->setVisible(false); disabledForSubdirsAspect()->setVisible(false); + // FIXME: Hack, Part#1: If the build device is not local, start with a temp dir + // inside the build dir. On Docker that's typically shared with the host. + const IDevice::ConstPtr device = BuildDeviceKitAspect::device(target()->kit()); + const bool hack = device && device->type() != ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE; + FilePath rootPath; + if (hack) { + rootPath = buildDirectory().pathAppended(".tmp-root"); + } else { + QTemporaryDir tmpDir; + rootPath = FilePath::fromString(tmpDir.path()); + } + const auto makeAspect = addAspect(parent->target(), ExecutableAspect::BuildDevice); makeAspect->setId(MakeAspectId); @@ -82,6 +96,7 @@ MakeInstallStep::MakeInstallStep(BuildStepList *parent, Id id) : MakeStep(parent installRootAspect->setDisplayStyle(StringAspect::PathChooserDisplay); installRootAspect->setExpectedKind(PathChooser::Directory); installRootAspect->setLabelText(tr("Install root:")); + installRootAspect->setFilePath(rootPath); connect(installRootAspect, &StringAspect::changed, this, &MakeInstallStep::updateArgsFromAspect); @@ -110,16 +125,14 @@ MakeInstallStep::MakeInstallStep(BuildStepList *parent, Id id) : MakeStep(parent updateArgsFromAspect(); updateFromCustomCommandLineAspect(); }; + connect(customCommandLineAspect, &StringAspect::checkedChanged, this, updateCommand); connect(customCommandLineAspect, &StringAspect::changed, this, &MakeInstallStep::updateFromCustomCommandLineAspect); connect(target(), &Target::buildSystemUpdated, this, updateCommand); - QTemporaryDir tmpDir; - installRootAspect->setFilePath(FilePath::fromString(tmpDir.path())); - - const MakeInstallCommand cmd = target()->makeInstallCommand(FilePath::fromString(tmpDir.path())); + const MakeInstallCommand cmd = buildSystem()->makeInstallCommand(rootPath); QTC_ASSERT(!cmd.command.isEmpty(), return); makeAspect->setExecutable(cmd.command.executable()); } @@ -168,7 +181,8 @@ bool MakeInstallStep::init() "last in the list of deploy steps. " "Consider moving it up."))); } - const MakeInstallCommand cmd = target()->makeInstallCommand(rootDir); + + const MakeInstallCommand cmd = buildSystem()->makeInstallCommand(rootDir); if (cmd.environment.isValid()) { Environment env = processParameters()->environment(); for (auto it = cmd.environment.constBegin(); it != cmd.environment.constEnd(); ++it) { @@ -192,6 +206,7 @@ bool MakeInstallStep::init() void MakeInstallStep::finish(bool success) { if (success) { + const bool hack = makeCommand().needsDevice(); const FilePath rootDir = installRoot().onDevice(makeCommand()); m_deploymentData = DeploymentData(); @@ -202,7 +217,7 @@ void MakeInstallStep::finish(bool success) const auto appFileNames = transform>(buildSystem()->applicationTargets(), [](const BuildTargetInfo &appTarget) { return appTarget.targetFilePath.fileName(); }); - auto handleFile = [this, &appFileNames, startPos](const FilePath &filePath) { + auto handleFile = [this, &appFileNames, startPos, hack](const FilePath &filePath) { const DeployableFile::Type type = appFileNames.contains(filePath.fileName()) ? DeployableFile::TypeExecutable : DeployableFile::TypeNormal; @@ -210,7 +225,13 @@ void MakeInstallStep::finish(bool success) // FIXME: This is conceptually the wrong place, but currently "downstream" like // the rsync step doesn't handle full remote paths here. targetDir = FilePath::fromString(targetDir).path(); - m_deploymentData.addFile(filePath, targetDir, type); + + // FIXME: Hack, Part#2: If the build was indeed not local, drop the remoteness. + // As we rely on shared build directory, this "maps" to the host. + if (hack) + m_deploymentData.addFile(FilePath::fromString(filePath.path()), targetDir, type); + else + m_deploymentData.addFile(filePath, targetDir, type); return true; }; rootDir.iterateDirectory(handleFile, @@ -255,8 +276,7 @@ void MakeInstallStep::updateArgsFromAspect() { if (customCommandLineAspect()->isChecked()) return; - - const CommandLine cmd = target()->makeInstallCommand(installRoot()).command; + const CommandLine cmd = buildSystem()->makeInstallCommand(installRoot()).command; setUserArguments(cmd.arguments()); updateFullCommandLine(); } diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.cpp b/src/plugins/remotelinux/publickeydeploymentdialog.cpp index 14d856a37ef..e8c0c3b6ce2 100644 --- a/src/plugins/remotelinux/publickeydeploymentdialog.cpp +++ b/src/plugins/remotelinux/publickeydeploymentdialog.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -74,7 +75,7 @@ PublicKeyDeploymentDialog::PublicKeyDeploymentDialog(const IDevice::ConstPtr &de connect(this, &PublicKeyDeploymentDialog::canceled, this, [this] { d->m_done ? accept() : reject(); }); connect(&d->m_process, &QtcProcess::done, this, [this] { - const bool succeeded = d->m_process.error() == QProcess::UnknownError; + const bool succeeded = d->m_process.result() == ProcessResult::FinishedWithSuccess; QString finalMessage; if (!succeeded) { QString errorMessage = d->m_process.errorString(); @@ -98,7 +99,33 @@ PublicKeyDeploymentDialog::PublicKeyDeploymentDialog(const IDevice::ConstPtr &de const QString command = "test -d .ssh || mkdir -p ~/.ssh && chmod 0700 .ssh && echo '" + QString::fromLocal8Bit(reader.data()) + "' >> .ssh/authorized_keys && chmod 0600 .ssh/authorized_keys"; - d->m_process.setCommand({deviceConfig->filePath("/bin/sh"), {"-c", command}}); + + const SshParameters params = deviceConfig->sshParameters(); + const QString hostKeyCheckingString = params.hostKeyCheckingMode == SshHostKeyCheckingStrict + ? QLatin1String("yes") : QLatin1String("no"); + const bool isWindows = HostOsInfo::isWindowsHost() + && SshSettings::sshFilePath().toString().toLower().contains("/system32/"); + const bool useTimeout = (params.timeout != 0) && !isWindows; + + Utils::CommandLine cmd{SshSettings::sshFilePath()}; + QStringList args{"-q", + "-o", "StrictHostKeyChecking=" + hostKeyCheckingString, + "-o", "Port=" + QString::number(params.port())}; + if (!params.userName().isEmpty()) + args << "-o" << "User=" + params.userName(); + args << "-o" << "BatchMode=no"; + if (useTimeout) + args << "-o" << "ConnectTimeout=" + QString::number(params.timeout); + args << params.host(); + cmd.addArgs(args); + + CommandLine execCmd; + execCmd.addArg("exec"); + execCmd.addCommandLineAsArgs({"/bin/sh", {"-c", command}}, CommandLine::Raw); + + cmd.addArg(execCmd.arguments()); + d->m_process.setCommand(cmd); + SshParameters::setupSshEnvironment(&d->m_process); d->m_process.start(); } diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index 859c8f249d7..8aaf6fbcc2e 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -19,8 +19,6 @@ Project { "abstractremotelinuxdeploystep.h", "deploymenttimeinfo.cpp", "deploymenttimeinfo.h", - "checkforfreediskspacestep.cpp", - "checkforfreediskspacestep.h", "customcommanddeploystep.cpp", "customcommanddeploystep.h", "genericdirectuploadservice.cpp", diff --git a/src/plugins/remotelinux/remotelinux_constants.h b/src/plugins/remotelinux/remotelinux_constants.h index da6eac43d40..909d327e5d3 100644 --- a/src/plugins/remotelinux/remotelinux_constants.h +++ b/src/plugins/remotelinux/remotelinux_constants.h @@ -32,7 +32,6 @@ const char GenericLinuxOsType[] = "GenericLinuxOsType"; const char DeployToGenericLinux[] = "DeployToGenericLinux"; -const char CheckForFreeDiskSpaceId[] = "RemoteLinux.CheckForFreeDiskSpaceStep"; const char DirectUploadStepId[] = "RemoteLinux.DirectUploadStep"; const char MakeInstallStepId[] = "RemoteLinux.MakeInstall"; const char TarPackageCreationStepId[] = "MaemoTarPackageCreationStep"; diff --git a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp index db5ecfc5280..37a44298017 100644 --- a/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp +++ b/src/plugins/remotelinux/remotelinuxdeployconfiguration.cpp @@ -63,7 +63,6 @@ RemoteLinuxDeployConfigurationFactory::RemoteLinuxDeployConfigurationFactory() }); addInitialStep(Constants::MakeInstallStepId, needsMakeInstall); - addInitialStep(Constants::CheckForFreeDiskSpaceId); addInitialStep(Constants::KillAppStepId); addInitialStep(Constants::RsyncDeployStepId, [](Target *target) { auto device = DeviceKitAspect::device(target->kit()); diff --git a/src/plugins/remotelinux/remotelinuxplugin.cpp b/src/plugins/remotelinux/remotelinuxplugin.cpp index 1f072a38a50..5e4cbd1c266 100644 --- a/src/plugins/remotelinux/remotelinuxplugin.cpp +++ b/src/plugins/remotelinux/remotelinuxplugin.cpp @@ -25,7 +25,6 @@ #include "remotelinuxplugin.h" -#include "checkforfreediskspacestep.h" #include "customcommanddeploystep.h" #include "genericdirectuploadstep.h" #include "killappstep.h" @@ -79,7 +78,6 @@ public: GenericDeployStepFactory genericDirectUploadStepFactory; GenericDeployStepFactory rsyncDeployStepFactory; CustomCommandDeployStepFactory customCommandDeployStepFactory; - GenericDeployStepFactory checkForFreeDiskSpaceStepFactory; GenericDeployStepFactory killAppStepFactory; GenericDeployStepFactory makeInstallStepFactory; diff --git a/src/plugins/remotelinux/sshprocessinterface.h b/src/plugins/remotelinux/sshprocessinterface.h index e60009ded2a..871c90d3ed6 100644 --- a/src/plugins/remotelinux/sshprocessinterface.h +++ b/src/plugins/remotelinux/sshprocessinterface.h @@ -60,10 +60,6 @@ private: qint64 write(const QByteArray &data) final; void sendControlSignal(Utils::ControlSignal controlSignal) override = 0; - bool waitForStarted(int msecs) final; - bool waitForReadyRead(int msecs) final; - bool waitForFinished(int msecs) final; - friend class SshProcessInterfacePrivate; SshProcessInterfacePrivate *d = nullptr; }; diff --git a/src/plugins/resourceeditor/resourcenode.cpp b/src/plugins/resourceeditor/resourcenode.cpp index 30070e7ec71..bc9274fa895 100644 --- a/src/plugins/resourceeditor/resourcenode.cpp +++ b/src/plugins/resourceeditor/resourcenode.cpp @@ -637,28 +637,4 @@ ResourceTopLevelNode *ResourceFolderNode::resourceNode() const return m_topLevelNode; } -ResourceFileNode::ResourceFileNode(const FilePath &filePath, const QString &qrcPath, const QString &displayName) - : FileNode(filePath, FileNode::fileTypeForFileName(filePath)) - , m_qrcPath(qrcPath) - , m_displayName(displayName) -{ -} - -QString ResourceFileNode::displayName() const -{ - return m_displayName; -} - -QString ResourceFileNode::qrcPath() const -{ - return m_qrcPath; -} - -bool ResourceFileNode::supportsAction(ProjectAction action, const Node *node) const -{ - if (action == HidePathActions) - return false; - return parentFolderNode()->supportsAction(action, node); -} - } // ResourceEditor diff --git a/src/plugins/resourceeditor/resourcenode.h b/src/plugins/resourceeditor/resourcenode.h index 03ae8039f0c..bb974cb2af5 100644 --- a/src/plugins/resourceeditor/resourcenode.h +++ b/src/plugins/resourceeditor/resourcenode.h @@ -91,18 +91,4 @@ private: QString m_lang; }; -class RESOURCE_EXPORT ResourceFileNode : public ProjectExplorer::FileNode -{ -public: - ResourceFileNode(const Utils::FilePath &filePath, const QString &qrcPath, const QString &displayName); - - QString displayName() const override; - QString qrcPath() const; - bool supportsAction(ProjectExplorer::ProjectAction action, const Node *node) const override; - -private: - QString m_qrcPath; - QString m_displayName; -}; - } // namespace ResourceEditor diff --git a/src/plugins/studiowelcome/studiowelcome.qbs b/src/plugins/studiowelcome/studiowelcome.qbs index 4c82c8112ec..7d254824ba5 100644 --- a/src/plugins/studiowelcome/studiowelcome.qbs +++ b/src/plugins/studiowelcome/studiowelcome.qbs @@ -2,6 +2,7 @@ import qbs.FileInfo QtcPlugin { name: "StudioWelcome" + condition: QmlDesigner.present Depends { name: "Qt"; submodules: ["qml", "qml-private", "quick", "quickwidgets"] } Depends { name: "Utils" } @@ -9,7 +10,7 @@ QtcPlugin { Depends { name: "Core" } Depends { name: "ProjectExplorer" } Depends { name: "QtSupport" } - Depends { name: "QmlDesigner" } + Depends { name: "QmlDesigner"; required: false } Depends { name: "QmlProjectManager" } Depends { name: "app_version_header" } diff --git a/src/plugins/texteditor/displaysettings.cpp b/src/plugins/texteditor/displaysettings.cpp index c5e41fb4991..f092150a0e6 100644 --- a/src/plugins/texteditor/displaysettings.cpp +++ b/src/plugins/texteditor/displaysettings.cpp @@ -47,6 +47,7 @@ static const char autoFoldFirstCommentKey[] = "AutoFoldFirstComment"; static const char centerCursorOnScrollKey[] = "CenterCursorOnScroll"; static const char openLinksInNextSplitKey[] = "OpenLinksInNextSplitKey"; static const char displayFileEncodingKey[] = "DisplayFileEncoding"; +static const char displayFileLineEndingKey[] = "DisplayFileLineEnding"; static const char scrollBarHighlightsKey[] = "ScrollBarHighlights"; static const char animateNavigationWithinFileKey[] = "AnimateNavigationWithinFile"; static const char animateWithinFileTimeMaxKey[] = "AnimateWithinFileTimeMax"; @@ -76,6 +77,7 @@ void DisplaySettings::toSettings(const QString &category, QSettings *s) const s->setValue(QLatin1String(centerCursorOnScrollKey), m_centerCursorOnScroll); s->setValue(QLatin1String(openLinksInNextSplitKey), m_openLinksInNextSplit); s->setValue(QLatin1String(displayFileEncodingKey), m_displayFileEncoding); + s->setValue(QLatin1String(displayFileLineEndingKey), m_displayFileLineEnding); s->setValue(QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights); s->setValue(QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile); s->setValue(QLatin1String(displayAnnotationsKey), m_displayAnnotations); @@ -105,6 +107,7 @@ void DisplaySettings::fromSettings(const QString &category, const QSettings *s) m_centerCursorOnScroll = s->value(group + QLatin1String(centerCursorOnScrollKey), m_centerCursorOnScroll).toBool(); m_openLinksInNextSplit = s->value(group + QLatin1String(openLinksInNextSplitKey), m_openLinksInNextSplit).toBool(); m_displayFileEncoding = s->value(group + QLatin1String(displayFileEncodingKey), m_displayFileEncoding).toBool(); + m_displayFileLineEnding = s->value(group + QLatin1String(displayFileLineEndingKey), m_displayFileLineEnding).toBool(); m_scrollBarHighlights = s->value(group + QLatin1String(scrollBarHighlightsKey), m_scrollBarHighlights).toBool(); m_animateNavigationWithinFile = s->value(group + QLatin1String(animateNavigationWithinFileKey), m_animateNavigationWithinFile).toBool(); m_animateWithinFileTimeMax = s->value(group + QLatin1String(animateWithinFileTimeMaxKey), m_animateWithinFileTimeMax).toInt(); @@ -131,6 +134,7 @@ bool DisplaySettings::equals(const DisplaySettings &ds) const && m_openLinksInNextSplit == ds.m_openLinksInNextSplit && m_forceOpenLinksInNextSplit == ds.m_forceOpenLinksInNextSplit && m_displayFileEncoding == ds.m_displayFileEncoding + && m_displayFileLineEnding == ds.m_displayFileLineEnding && m_scrollBarHighlights == ds.m_scrollBarHighlights && m_animateNavigationWithinFile == ds.m_animateNavigationWithinFile && m_animateWithinFileTimeMax == ds.m_animateWithinFileTimeMax diff --git a/src/plugins/texteditor/displaysettings.h b/src/plugins/texteditor/displaysettings.h index ae87f76dfbd..97b716a8fc7 100644 --- a/src/plugins/texteditor/displaysettings.h +++ b/src/plugins/texteditor/displaysettings.h @@ -69,6 +69,7 @@ public: bool m_openLinksInNextSplit = false; bool m_forceOpenLinksInNextSplit = false; bool m_displayFileEncoding = false; + bool m_displayFileLineEnding = true; bool m_scrollBarHighlights = true; bool m_animateNavigationWithinFile = false; int m_animateWithinFileTimeMax = 333; // read only setting diff --git a/src/plugins/texteditor/displaysettingspage.cpp b/src/plugins/texteditor/displaysettingspage.cpp index fa551504211..f972e1735a8 100644 --- a/src/plugins/texteditor/displaysettingspage.cpp +++ b/src/plugins/texteditor/displaysettingspage.cpp @@ -102,6 +102,7 @@ void DisplaySettingsWidget::settingsFromUI(DisplaySettings &displaySettings, displaySettings.m_centerCursorOnScroll = m_ui.centerOnScroll->isChecked(); displaySettings.m_openLinksInNextSplit = m_ui.openLinksInNextSplit->isChecked(); displaySettings.m_displayFileEncoding = m_ui.displayFileEncoding->isChecked(); + displaySettings.m_displayFileLineEnding = m_ui.displayFileLineEnding->isChecked(); displaySettings.m_scrollBarHighlights = m_ui.scrollBarHighlights->isChecked(); displaySettings.m_animateNavigationWithinFile = m_ui.animateNavigationWithinFile->isChecked(); displaySettings.m_displayAnnotations = m_ui.displayAnnotations->isChecked(); @@ -135,6 +136,7 @@ void DisplaySettingsWidget::settingsToUI() m_ui.centerOnScroll->setChecked(displaySettings.m_centerCursorOnScroll); m_ui.openLinksInNextSplit->setChecked(displaySettings.m_openLinksInNextSplit); m_ui.displayFileEncoding->setChecked(displaySettings.m_displayFileEncoding); + m_ui.displayFileLineEnding->setChecked(displaySettings.m_displayFileLineEnding); m_ui.scrollBarHighlights->setChecked(displaySettings.m_scrollBarHighlights); m_ui.animateNavigationWithinFile->setChecked(displaySettings.m_animateNavigationWithinFile); m_ui.displayAnnotations->setChecked(displaySettings.m_displayAnnotations); diff --git a/src/plugins/texteditor/displaysettingspage.ui b/src/plugins/texteditor/displaysettingspage.ui index c7d49ac0692..29dea5649a3 100644 --- a/src/plugins/texteditor/displaysettingspage.ui +++ b/src/plugins/texteditor/displaysettingspage.ui @@ -97,6 +97,13 @@ + + + + Display file line ending + + + @@ -170,7 +177,7 @@ - + Animate navigation within file diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index eb33c6de6a3..22c23387d3a 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -640,6 +640,7 @@ public: void slotSelectionChanged(); void _q_animateUpdate(const QTextCursor &cursor, QPointF lastPos, QRectF rect); void updateCodeFoldingVisible(); + void updateFileLineEndingVisible(); void reconfigure(); void updateSyntaxInfoBar(const Highlighter::Definitions &definitions, const QString &fileName); @@ -952,10 +953,9 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent) m_fileLineEnding->addItems(ExtraEncodingSettings::lineTerminationModeNames()); m_fileLineEnding->setContentsMargins(spacing, 0, spacing, 0); m_fileLineEndingAction = m_toolBar->addWidget(m_fileLineEnding); - m_fileLineEndingAction->setVisible(!q->isReadOnly()); - connect(q, &TextEditorWidget::readOnlyChanged, this, [this] { - m_fileLineEndingAction->setVisible(!q->isReadOnly()); - }); + updateFileLineEndingVisible(); + connect(q, &TextEditorWidget::readOnlyChanged, + this, &TextEditorWidgetPrivate::updateFileLineEndingVisible); m_fileEncodingLabel = new FixedSizeClickLabel; m_fileEncodingLabel->setContentsMargins(spacing, 0, spacing, 0); @@ -3225,6 +3225,11 @@ void TextEditorWidgetPrivate::updateCodeFoldingVisible() } } +void TextEditorWidgetPrivate::updateFileLineEndingVisible() +{ + m_fileLineEndingAction->setVisible(m_displaySettings.m_displayFileLineEnding && !q->isReadOnly()); +} + void TextEditorWidgetPrivate::reconfigure() { m_document->setMimeType(Utils::mimeTypeForFile(m_document->filePath()).name()); @@ -7211,6 +7216,7 @@ void TextEditorWidget::setDisplaySettings(const DisplaySettings &ds) } d->updateCodeFoldingVisible(); + d->updateFileLineEndingVisible(); d->updateHighlights(); d->setupScrollBar(); viewport()->update(); diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp index 5a0df2d1de1..ed840b1d428 100644 --- a/src/plugins/texteditor/texteditorsettings.cpp +++ b/src/plugins/texteditor/texteditorsettings.cpp @@ -373,46 +373,57 @@ FormatDescriptions TextEditorSettingsPrivate::initialFormats() tr("Names of static fields or member functions."), FormatDescription::ShowAllControls); + const auto cocoControls = FormatDescription::ShowControls( + FormatDescription::ShowAllAbsoluteControls | FormatDescription::ShowRelativeControls); formatDescr.emplace_back(C_COCO_CODE_ADDED, tr("Code Coverage Added Code"), tr("New code that was not checked for tests."), - FormatDescription::ShowAllControls); + cocoControls); formatDescr.emplace_back(C_COCO_PARTIALLY_COVERED, tr("Partially Covered Code"), tr("Partial branch/condition coverage."), - FormatDescription::ShowAllControls); + Qt::darkYellow, + cocoControls); formatDescr.emplace_back(C_COCO_NOT_COVERED, tr("Uncovered Code"), tr("Not covered at all."), - FormatDescription::ShowAllControls); + Qt::red, + cocoControls); formatDescr.emplace_back(C_COCO_FULLY_COVERED, tr("Fully Covered Code"), tr("Fully covered code."), - FormatDescription::ShowAllControls); + Qt::green, + cocoControls); formatDescr.emplace_back(C_COCO_MANUALLY_VALIDATED, tr("Manually Validated Code"), tr("User added validation."), - FormatDescription::ShowAllControls); + Qt::blue, + cocoControls); formatDescr.emplace_back(C_COCO_DEAD_CODE, tr("Code Coverage Dead Code"), tr("Unreachable code."), - FormatDescription::ShowAllControls); + Qt::magenta, + cocoControls); formatDescr.emplace_back(C_COCO_EXECUTION_COUNT_TOO_LOW, - tr("Code Coverage Execution Count To Low"), + tr("Code Coverage Execution Count Too Low"), tr("Minimum count not reached."), - FormatDescription::ShowAllControls); + Qt::red, + cocoControls); formatDescr.emplace_back(C_COCO_NOT_COVERED_INFO, tr("Implicitly Not Covered Code"), tr("PLACEHOLDER"), - FormatDescription::ShowAllControls); + Qt::red, + cocoControls); formatDescr.emplace_back(C_COCO_COVERED_INFO, tr("Implicitly Covered Code"), tr("PLACEHOLDER"), - FormatDescription::ShowAllControls); + Qt::green, + cocoControls); formatDescr.emplace_back(C_COCO_MANUALLY_VALIDATED_INFO, tr("Implicit Manual Coverage Validation"), tr("PLACEHOLDER"), - FormatDescription::ShowAllControls); + Qt::blue, + cocoControls); return formatDescr; } diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index c895d3c65a5..a0617df3a09 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -254,9 +254,9 @@ static void showQtUpdateInfo(const QtPackage &package, { Utils::InfoBarEntry info(InstallQtUpdates, UpdateInfoPlugin::tr( - "%1 is available. Check the Qt blog for details.") - .arg(package.displayName)); + "%1 is available. Check the Qt blog for details.") + .arg(package.displayName, + QString("href=\"https://www.qt.io/blog/tag/releases\""))); info.addCustomButton(UpdateInfoPlugin::tr("Start Package Manager"), [startPackageManager] { Core::ICore::infoBar()->removeInfo(InstallQtUpdates); startPackageManager(); diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp index ec817b1f61b..b547edc802a 100644 --- a/src/plugins/valgrind/valgrindrunner.cpp +++ b/src/plugins/valgrind/valgrindrunner.cpp @@ -50,6 +50,7 @@ public: bool run(); void processStarted(); + void processDone(); void localProcessStarted(); void remoteProcessStarted(); void findPidProcessDone(); @@ -65,7 +66,6 @@ public: QHostAddress localServerAddress; QProcess::ProcessChannelMode channelMode = QProcess::SeparateChannels; - bool m_finished = false; QTcpServer xmlServer; XmlProtocol::ThreadedParser parser; @@ -116,12 +116,10 @@ bool ValgrindRunner::Private::run() // consider appending our options last so they override any interfering user-supplied options // -q as suggested by valgrind manual - connect(&m_valgrindProcess, &QtcProcess::finished, - q, &ValgrindRunner::processFinished); connect(&m_valgrindProcess, &QtcProcess::started, this, &ValgrindRunner::Private::processStarted); - connect(&m_valgrindProcess, &QtcProcess::errorOccurred, - q, &ValgrindRunner::processError); + connect(&m_valgrindProcess, &QtcProcess::done, + this, &ValgrindRunner::Private::processDone); connect(&m_valgrindProcess, &QtcProcess::readyReadStandardOutput, q, [this] { q->processOutputReceived(QString::fromUtf8(m_valgrindProcess.readAllStandardOutput()), @@ -145,7 +143,6 @@ bool ValgrindRunner::Private::run() m_valgrindProcess.setWorkingDirectory(m_debuggee.workingDirectory); m_valgrindProcess.setEnvironment(m_debuggee.environment); m_valgrindProcess.start(); - return true; } @@ -157,6 +154,17 @@ void ValgrindRunner::Private::processStarted() remoteProcessStarted(); } +void ValgrindRunner::Private::processDone() +{ + emit q->extraProcessFinished(); + + if (m_valgrindProcess.result() != ProcessResult::FinishedWithSuccess) + emit q->processErrorReceived(m_valgrindProcess.errorString(), m_valgrindProcess.error()); + + // make sure we don't wait for the connection anymore + emit q->finished(); +} + void ValgrindRunner::Private::localProcessStarted() { qint64 pid = m_valgrindProcess.processId(); @@ -268,7 +276,7 @@ void ValgrindRunner::setUseTerminal(bool on) void ValgrindRunner::waitForFinished() const { - if (d->m_finished) + if (d->m_valgrindProcess.state() == QProcess::NotRunning) return; QEventLoop loop; @@ -281,42 +289,9 @@ bool ValgrindRunner::start() return d->run(); } -void ValgrindRunner::processError(QProcess::ProcessError e) -{ - if (d->m_finished) - return; - - d->m_finished = true; - - // make sure we don't wait for the connection anymore - emit processErrorReceived(errorString(), e); - emit finished(); -} - -void ValgrindRunner::processFinished() -{ - emit extraProcessFinished(); - - if (d->m_finished) - return; - - d->m_finished = true; - - // make sure we don't wait for the connection anymore - emit finished(); - - if (d->m_valgrindProcess.exitCode() != 0 || d->m_valgrindProcess.exitStatus() == QProcess::CrashExit) - emit processErrorReceived(errorString(), d->m_valgrindProcess.error()); -} - -QString ValgrindRunner::errorString() const -{ - return d->m_valgrindProcess.errorString(); -} - void ValgrindRunner::stop() { - d->m_valgrindProcess.close(); + d->m_valgrindProcess.stop(); } XmlProtocol::ThreadedParser *ValgrindRunner::parser() const diff --git a/src/plugins/valgrind/valgrindrunner.h b/src/plugins/valgrind/valgrindrunner.h index 7ba28b1392c..3350792b51f 100644 --- a/src/plugins/valgrind/valgrindrunner.h +++ b/src/plugins/valgrind/valgrindrunner.h @@ -57,8 +57,6 @@ public: void waitForFinished() const; - QString errorString() const; - bool start(); void stop(); @@ -75,8 +73,6 @@ signals: private: bool startServers(); - void processError(QProcess::ProcessError); - void processFinished(); void xmlSocketConnected(); void logSocketConnected(); diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp index b371c8b2f64..74edfd3dd34 100644 --- a/src/plugins/vcsbase/vcsbaseplugin.cpp +++ b/src/plugins/vcsbase/vcsbaseplugin.cpp @@ -199,7 +199,7 @@ public: explicit StateListener(QObject *parent); ~StateListener(); - static QString windowTitleVcsTopic(const QString &filePath); + static QString windowTitleVcsTopic(const FilePath &filePath); signals: void stateChanged(const VcsBase::Internal::State &s, IVersionControl *vc); @@ -230,11 +230,11 @@ StateListener::~StateListener() EditorManager::setWindowTitleVcsTopicHandler({}); } -QString StateListener::windowTitleVcsTopic(const QString &filePath) +QString StateListener::windowTitleVcsTopic(const FilePath &filePath) { FilePath searchPath; if (!filePath.isEmpty()) { - searchPath = FilePath::fromString(filePath).absolutePath(); + searchPath = filePath.absolutePath(); } else { // use single project's information if there is only one loaded. const QList projects = SessionManager::projects(); diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index b405bf40b1d..ae8d877452a 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -669,7 +669,6 @@ bool VcsBaseSubmitEditor::runSubmitMessageCheckScript(const QString &checkScript QByteArray stdOutData; QByteArray stdErrData; if (!checkProcess.readDataFromProcess(30, &stdOutData, &stdErrData, false)) { - checkProcess.stopProcess(); *errorMessage = tr("The check script \"%1\" timed out."). arg(QDir::toNativeSeparators(checkScript)); return false; diff --git a/src/tools/iostool/CMakeLists.txt b/src/tools/iostool/CMakeLists.txt index e02bf7463d4..b7efdc1abda 100644 --- a/src/tools/iostool/CMakeLists.txt +++ b/src/tools/iostool/CMakeLists.txt @@ -18,6 +18,7 @@ add_qtc_executable(iostool main.cpp mobiledevicelib.cpp mobiledevicelib.h relayserver.cpp relayserver.h + cfutils.h ) if (TARGET iostool) diff --git a/src/plugins/remotelinux/checkforfreediskspacestep.h b/src/tools/iostool/cfutils.h similarity index 57% rename from src/plugins/remotelinux/checkforfreediskspacestep.h rename to src/tools/iostool/cfutils.h index e1ff4c3765e..94e8452f0ce 100644 --- a/src/plugins/remotelinux/checkforfreediskspacestep.h +++ b/src/tools/iostool/cfutils.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. @@ -25,21 +25,31 @@ #pragma once -#include "remotelinux_export.h" +#include -#include "abstractremotelinuxdeploystep.h" +#include -namespace RemoteLinux { +namespace Ios { -class REMOTELINUX_EXPORT CheckForFreeDiskSpaceStep : public AbstractRemoteLinuxDeployStep +template +struct CFRefDeleter { - Q_OBJECT - -public: - CheckForFreeDiskSpaceStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); - - static Utils::Id stepId(); - static QString displayName(); + using pointer = CFType; + void operator()(CFType ref) { CFRelease(ref); } }; -} // namespace RemoteLinux +inline QString toQStringRelease(CFStringRef str) +{ + QString result = QString::fromCFString(str); + CFRelease(str); + return result; +} + +using CFString_t = std::unique_ptr>; +using CFUrl_t = std::unique_ptr>; +using CFPropertyList_t = std::unique_ptr>; +using CFBundle_t = std::unique_ptr>; +using CFDictionary_t = std::unique_ptr>; +using CFArray_t = std::unique_ptr>; + +} // namespace Ios diff --git a/src/tools/iostool/iosdevicemanager.cpp b/src/tools/iostool/iosdevicemanager.cpp index 2e6aa4ccf36..781420beeb0 100644 --- a/src/tools/iostool/iosdevicemanager.cpp +++ b/src/tools/iostool/iosdevicemanager.cpp @@ -25,19 +25,19 @@ #include "iosdevicemanager.h" +#include "cfutils.h" #include "mobiledevicelib.h" -#include #include #include #include #include +#include #include #include #include #include #include -#include #include #include #include @@ -54,6 +54,10 @@ static const bool debugAll = false; static const bool verbose = true; static const bool noWifi = true; +namespace { + Q_LOGGING_CATEGORY(loggingCategory, "qtc.iostool.iosdevicemanager", QtWarningMsg) +} + // ------- MobileDeviceLib interface -------- namespace { @@ -277,8 +281,12 @@ public: static IosDeviceManagerPrivate *instance(); explicit IosDeviceManagerPrivate (IosDeviceManager *q); bool watchDevices(); - void requestAppOp(const QString &bundlePath, const QStringList &extraArgs, - Ios::IosDeviceManager::AppOp appOp, const QString &deviceId, int timeout); + void requestAppOp(const QString &bundlePath, + const QStringList &extraArgs, + Ios::IosDeviceManager::AppOp appOp, + const QString &deviceId, + int timeout, + const QString &deltaPath); void requestDeviceInfo(const QString &deviceId, int timeout); QStringList errors(); void addError(QString errorMsg); @@ -321,13 +329,17 @@ public: QString bundlePath; QStringList extraArgs; Ios::IosDeviceManager::AppOp appOp; + QString deltaPath; - - AppOpSession(const QString &deviceId, const QString &bundlePath, - const QStringList &extraArgs, Ios::IosDeviceManager::AppOp appOp); + AppOpSession(const QString &deviceId, + const QString &bundlePath, + const QStringList &extraArgs, + Ios::IosDeviceManager::AppOp appOp, + const QString &deltaPath); void deviceCallbackReturned() override; bool installApp(); + bool installAppNew(); bool runApp(); int qmljsDebugPort() const override; am_res_t appTransferCallback(CFDictionaryRef dict) override; @@ -486,11 +498,13 @@ bool IosDeviceManagerPrivate::watchDevices() } void IosDeviceManagerPrivate::requestAppOp(const QString &bundlePath, - const QStringList &extraArgs, - IosDeviceManager::AppOp appOp, - const QString &deviceId, int timeout) + const QStringList &extraArgs, + IosDeviceManager::AppOp appOp, + const QString &deviceId, + int timeout, + const QString &deltaPath) { - AppOpSession *session = new AppOpSession(deviceId, bundlePath, extraArgs, appOp); + AppOpSession *session = new AppOpSession(deviceId, bundlePath, extraArgs, appOp, deltaPath); session->startDeviceLookup(timeout); } @@ -1205,10 +1219,17 @@ bool CommandSession::developerDiskImagePath(QString *path, QString *signaturePat return false; } -AppOpSession::AppOpSession(const QString &deviceId, const QString &bundlePath, - const QStringList &extraArgs, IosDeviceManager::AppOp appOp): - CommandSession(deviceId), bundlePath(bundlePath), extraArgs(extraArgs), appOp(appOp) -{ } +AppOpSession::AppOpSession(const QString &deviceId, + const QString &bundlePath, + const QStringList &extraArgs, + IosDeviceManager::AppOp appOp, + const QString &deltaPath) + : CommandSession(deviceId) + , bundlePath(bundlePath) + , extraArgs(extraArgs) + , appOp(appOp) + , deltaPath(deltaPath) +{} QString AppOpSession::commandName() { @@ -1218,70 +1239,143 @@ QString AppOpSession::commandName() bool AppOpSession::installApp() { bool success = false; - if (device != 0) { - CFURLRef bundleUrl = QUrl::fromLocalFile(bundlePath).toCFURL(); - CFStringRef key[1] = {CFSTR("PackageType")}; - CFStringRef value[1] = {CFSTR("Developer")}; - CFDictionaryRef options = CFDictionaryCreate(0, reinterpret_cast(&key[0]), - reinterpret_cast(&value[0]), 1, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + if (device) { + if (!installAppNew()) { + addError(QString::fromLatin1( + "Failed to transfer and install application, trying old way ...")); - MobileDeviceLib &mLib = MobileDeviceLib::instance(); - // Transfer bundle with secure API AMDeviceTransferApplication. - if (int error = mLib.deviceSecureTransferApplicationPath(0, device, bundleUrl, options, - &appSecureTransferSessionCallback,0)) { - addError(QString::fromLatin1("TransferAppSession(%1,%2) failed, AMDeviceTransferApplication returned %3 (0x%4)") - .arg(bundlePath, deviceId).arg(mobileDeviceErrorString(error)).arg(error)); - success = false; - } else { - // App is transferred. Try installing. - if (connectDevice()) { - // Secure install app api requires device to be connected. - if (am_res_t error = mLib.deviceSecureInstallApplication(0, device, bundleUrl, options, - &appSecureTransferSessionCallback,0)) { - const QString errorString = mobileDeviceErrorString(error); - if (!errorString.isEmpty()) { - addError(errorString - + QStringLiteral(" (0x") - + QString::number(error, 16) - + QStringLiteral(")")); + const CFUrl_t bundleUrl(QUrl::fromLocalFile(bundlePath).toCFURL()); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + + CFStringRef key[1] = {CFSTR("PackageType")}; + CFStringRef value[1] = {CFSTR("Developer")}; + const CFDictionary_t options( + CFDictionaryCreate(0, + reinterpret_cast(&key[0]), + reinterpret_cast(&value[0]), + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + // Transfer bundle with secure API AMDeviceTransferApplication. + if (int error + = mLib.deviceSecureTransferApplicationPath(0, + device, + bundleUrl.get(), + options.get(), + &appSecureTransferSessionCallback, + 0)) { + addError(QString::fromLatin1("TransferAppSession(%1,%2) failed, " + "AMDeviceTransferApplication returned %3 (0x%4)") + .arg(bundlePath, deviceId) + .arg(mobileDeviceErrorString(error)) + .arg(error)); + success = false; + } else { + // App is transferred. Try installing. + if (connectDevice()) { + // Secure install app api requires device to be connected. + if (am_res_t error + = mLib.deviceSecureInstallApplication(0, + device, + bundleUrl.get(), + options.get(), + &appSecureTransferSessionCallback, + 0)) { + const QString errorString = mobileDeviceErrorString(error); + if (!errorString.isEmpty()) { + addError(errorString + QStringLiteral(" (0x") + + QString::number(error, 16) + QStringLiteral(")")); + } else { + addError(QString::fromLatin1("InstallAppSession(%1,%2) failed, " + "AMDeviceInstallApplication returned 0x%3") + .arg(bundlePath, deviceId) + .arg(QString::number(error, 16))); + } + success = false; } else { - addError(QString::fromLatin1("InstallAppSession(%1,%2) failed, " - "AMDeviceInstallApplication returned 0x%3") - .arg(bundlePath, deviceId).arg(QString::number(error, 16))); + // App is installed. + success = true; } - success = false; - } else { - // App is installed. - success = true; + disconnectDevice(); } - disconnectDevice(); } + } else { + success = true; } - if (debugAll) { - qDebug() << "AMDeviceSecureTransferApplication finished request with " << (success ? "Success" : "Failure"); - } - - CFRelease(options); - CFRelease(bundleUrl); + qCDebug(loggingCategory) << "AMDeviceSecureTransferApplication finished request with" + << (success ? "Success" : "Failure"); progressBase += 100; } - if (success) { sleep(5); // after installation the device needs a bit of quiet.... } - if (debugAll) { - qDebug() << "AMDeviceSecureInstallApplication finished request with " << (success ? "Success" : "Failure"); + qCDebug(loggingCategory) << "AMDeviceSecureInstallApplication finished request with" + << (success ? "Success" : "Failure"); + + IosDeviceManagerPrivate::instance()->didTransferApp(bundlePath, + deviceId, + (success ? IosDeviceManager::Success + : IosDeviceManager::Failure)); + return success; +} + +bool AppOpSession::installAppNew() +{ + const CFUrl_t bundleUrl(QUrl::fromLocalFile(bundlePath).toCFURL()); + MobileDeviceLib &mLib = MobileDeviceLib::instance(); + + CFBundle_t bundle(CFBundleCreate(kCFAllocatorDefault, bundleUrl.get())); + + if (!bundle) { + addError(QString::fromLatin1("Failed to create bundle")); + return false; } - IosDeviceManagerPrivate::instance()->didTransferApp(bundlePath, deviceId, - (success ? IosDeviceManager::Success : IosDeviceManager::Failure)); - return success; + const CFString_t bundleId(CFBundleGetIdentifier(bundle.get())); + if (!bundleId) { + addError(QString::fromLatin1("Failed to retrieve bundle id")); + return false; + } + + CFUrl_t dpath(QUrl::fromLocalFile(deltaPath).toCFURL()); + + CFStringRef keys[] = { + CFSTR("CFBundleIdentifier"), + CFSTR("CloseOnInvalidate"), + CFSTR("InvalidateOnDetach"), + CFSTR("IsUserInitiated"), + CFSTR("PackageType"), + CFSTR("PreferWifi"), + CFSTR("ShadowParentKey"), + }; + CFStringRef values[] = {bundleId.get(), + CFSTR("1"), + CFSTR("1"), + CFSTR("1"), + CFSTR("Developer"), + CFSTR("1"), + (CFStringRef)dpath.get()}; + + const CFDictionary_t options(CFDictionaryCreate(0, + reinterpret_cast(&keys[0]), + reinterpret_cast(&values[0]), + 7, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + + if (int error = mLib.deviceSecureInstallApplicationBundle(0, + device, + bundleUrl.get(), + options.get(), + &appSecureTransferSessionCallback)) + return false; + + return true; } void AppOpSession::deviceCallbackReturned() @@ -1575,9 +1669,14 @@ bool IosDeviceManager::watchDevices() { return d->watchDevices(); } -void IosDeviceManager::requestAppOp(const QString &bundlePath, const QStringList &extraArgs, - AppOp appOp, const QString &deviceId, int timeout) { - d->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout); +void IosDeviceManager::requestAppOp(const QString &bundlePath, + const QStringList &extraArgs, + AppOp appOp, + const QString &deviceId, + int timeout, + QString deltaPath) +{ + d->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout, deltaPath); } void IosDeviceManager::requestDeviceInfo(const QString &deviceId, int timeout) diff --git a/src/tools/iostool/iosdevicemanager.h b/src/tools/iostool/iosdevicemanager.h index 7c521c789fd..2fb3bb1c3a3 100644 --- a/src/tools/iostool/iosdevicemanager.h +++ b/src/tools/iostool/iosdevicemanager.h @@ -62,7 +62,7 @@ public: static IosDeviceManager *instance(); bool watchDevices(); void requestAppOp(const QString &bundlePath, const QStringList &extraArgs, AppOp appOp, - const QString &deviceId, int timeout = 1000); + const QString &deviceId, int timeout = 1000, QString deltaPath = QString()); void requestDeviceInfo(const QString &deviceId, int timeout = 1000); int processGdbServer(ServiceConnRef conn); void stopGdbServer(ServiceConnRef conn, int phase); diff --git a/src/tools/iostool/iostool.cpp b/src/tools/iostool/iostool.cpp index e65cae852a4..2def3afa74a 100644 --- a/src/tools/iostool/iostool.cpp +++ b/src/tools/iostool/iostool.cpp @@ -82,6 +82,12 @@ void IosTool::run(const QStringList &args) printHelp = true; } bundlePath = args.value(iarg); + } else if (arg == QLatin1String("--delta-path")) { + if (++iarg == args.size()) { + writeMsg(QStringLiteral("missing path after ") + arg); + printHelp = true; + } + m_deltasPath = args.value(iarg); } else if (arg == QLatin1String("--install")) { appOp = IosDeviceManager::AppOp(appOp | IosDeviceManager::Install); } else if (arg == QLatin1String("--run")) { @@ -163,7 +169,7 @@ void IosTool::run(const QStringList &args) break; } maxProgress = 200; - manager->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout); + manager->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout, m_deltasPath); } if (opLeft == 0) doExit(0); diff --git a/src/tools/iostool/iostool.h b/src/tools/iostool/iostool.h index 6aa85216ca0..c71a30e6d8c 100644 --- a/src/tools/iostool/iostool.h +++ b/src/tools/iostool/iostool.h @@ -79,6 +79,7 @@ private: Ios::IosDeviceManager::AppOp appOp; QFile outFile; QString m_qmlPort; + QString m_deltasPath; QXmlStreamWriter out; GdbRelayServer *gdbServer; QmlRelayServer *qmlServer; diff --git a/src/tools/iostool/iostool.qbs b/src/tools/iostool/iostool.qbs index a39ace4dba1..d45172e23f2 100644 --- a/src/tools/iostool/iostool.qbs +++ b/src/tools/iostool/iostool.qbs @@ -11,6 +11,7 @@ QtcTool { Depends { name: "app_version_header" } files: [ + "cfutils.h", "Info.plist", "gdbrunner.cpp", "gdbrunner.h", diff --git a/src/tools/iostool/mobiledevicelib.cpp b/src/tools/iostool/mobiledevicelib.cpp index 025248262f1..ae1c70f4a86 100644 --- a/src/tools/iostool/mobiledevicelib.cpp +++ b/src/tools/iostool/mobiledevicelib.cpp @@ -89,7 +89,15 @@ bool MobileDeviceLib::load() m_AMDSetLogLevel = reinterpret_cast(lib.resolve("AMDSetLogLevel")); if (m_AMDSetLogLevel == 0) addError("MobileDeviceLib does not define AMDSetLogLevel"); - m_AMDeviceNotificationSubscribe = reinterpret_cast(lib.resolve("AMDeviceNotificationSubscribe")); + + m_AMDeviceSecureInstallApplicationBundle + = reinterpret_cast( + lib.resolve("AMDeviceSecureInstallApplicationBundle")); + if (m_AMDeviceSecureInstallApplicationBundle == 0) + addError("MobileDeviceLib does not define m_AMDeviceSecureInstallApplicationBundle"); + + m_AMDeviceNotificationSubscribe = reinterpret_cast( + lib.resolve("AMDeviceNotificationSubscribe")); if (m_AMDeviceNotificationSubscribe == 0) addError("MobileDeviceLib does not define AMDeviceNotificationSubscribe"); m_AMDeviceNotificationUnsubscribe = reinterpret_cast(lib.resolve("AMDeviceNotificationUnsubscribe")); @@ -358,6 +366,21 @@ int MobileDeviceLib::deviceSecureTransferApplicationPath(int zero, AMDeviceRef d return returnCode; } +int MobileDeviceLib::deviceSecureInstallApplicationBundle( + int zero, + AMDeviceRef device, + CFURLRef url, + CFDictionaryRef options, + AMDeviceSecureInstallApplicationCallback callback) +{ + int returnCode = -1; + + if (m_AMDeviceSecureInstallApplicationBundle) { + returnCode = m_AMDeviceSecureInstallApplicationBundle(device, url, options, callback, zero); + } + return returnCode; +} + int MobileDeviceLib::deviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, AMDeviceSecureInstallApplicationCallback callback, int arg) { int returnCode = -1; diff --git a/src/tools/iostool/mobiledevicelib.h b/src/tools/iostool/mobiledevicelib.h index 97735fdcb1a..68bca9d316d 100644 --- a/src/tools/iostool/mobiledevicelib.h +++ b/src/tools/iostool/mobiledevicelib.h @@ -101,6 +101,7 @@ typedef am_res_t (MDEV_API *USBMuxConnectByPortPtr)(unsigned int, int, ServiceSo // secure Api's typedef am_res_t (MDEV_API *AMDeviceSecureStartServicePtr)(AMDeviceRef, CFStringRef, unsigned int *, ServiceConnRef *); typedef int (MDEV_API *AMDeviceSecureTransferPathPtr)(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int); +typedef int (MDEV_API *AMDeviceSecureInstallApplicationBundlePtr)(AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int zero); typedef int (MDEV_API *AMDeviceSecureInstallApplicationPtr)(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int); typedef int (MDEV_API *AMDServiceConnectionGetSocketPtr)(ServiceConnRef); @@ -158,6 +159,13 @@ public: int deviceSecureTransferApplicationPath(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback callback, int); + + int deviceSecureInstallApplicationBundle(int zero, + AMDeviceRef device, + CFURLRef url, + CFDictionaryRef options, + AMDeviceSecureInstallApplicationCallback callback); + int deviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, AMDeviceSecureInstallApplicationCallback callback, int arg); @@ -191,6 +199,7 @@ private: AMDeviceMountImagePtr m_AMDeviceMountImage; AMDeviceSecureStartServicePtr m_AMDeviceSecureStartService; AMDeviceSecureTransferPathPtr m_AMDeviceSecureTransferPath; + AMDeviceSecureInstallApplicationBundlePtr m_AMDeviceSecureInstallApplicationBundle; AMDeviceSecureInstallApplicationPtr m_AMDeviceSecureInstallApplication; AMDServiceConnectionGetSocketPtr m_AMDServiceConnectionGetSocket; AMDServiceConnectionSendPtr m_AMDServiceConnectionSend; diff --git a/tests/auto/utils/qtcprocess/CMakeLists.txt b/tests/auto/utils/qtcprocess/CMakeLists.txt index 51720bbeb5b..c03eee4945b 100644 --- a/tests/auto/utils/qtcprocess/CMakeLists.txt +++ b/tests/auto/utils/qtcprocess/CMakeLists.txt @@ -4,6 +4,7 @@ file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_B file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}") add_qtc_test(tst_qtcprocess + TIMEOUT 30 DEFINES "TEST_RELATIVE_LIBEXEC_PATH=\"${TEST_RELATIVE_LIBEXEC_PATH}\"" "PROCESS_TESTAPP=\"${CMAKE_CURRENT_BINARY_DIR}/processtestapp\"" DEPENDS Utils app_version diff --git a/tests/unit/unittest/unittest.qbs b/tests/unit/unittest/unittest.qbs index 00f3e2a8c64..3828063b783 100644 --- a/tests/unit/unittest/unittest.qbs +++ b/tests/unit/unittest/unittest.qbs @@ -6,7 +6,8 @@ Project { QtcProduct { name: "Unit test" - condition: qtc_gtest_gmock.hasRepo || qtc_gtest_gmock.externalLibsPresent + condition: (qtc_gtest_gmock.hasRepo || qtc_gtest_gmock.externalLibsPresent) + && QmlDesigner.present type: ["application", "autotest"] consoleApplication: true @@ -17,7 +18,7 @@ Project { Depends { name: "libclang"; required: false } Depends { name: "clang_defines" } - Depends { name: "QmlDesigner" } + Depends { name: "QmlDesigner"; required: false } Depends { name: "sqlite_sources" } Depends { name: "Core" }