diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 7e7c91d6a21..ed0a3958f3e 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -7,7 +7,7 @@ on: - 'doc/**' env: - QT_VERSION: 6.3.0 + QT_VERSION: 6.3.1 CLANG_VERSION: 14.0.3 ELFUTILS_VERSION: 0.175 CMAKE_VERSION: 3.21.1 diff --git a/cmake/QtCreatorIDEBranding.cmake b/cmake/QtCreatorIDEBranding.cmake index 3ca492689c7..92a3d31689c 100644 --- a/cmake/QtCreatorIDEBranding.cmake +++ b/cmake/QtCreatorIDEBranding.cmake @@ -1,6 +1,6 @@ -set(IDE_VERSION "7.82.0") # The IDE version. -set(IDE_VERSION_COMPAT "7.82.0") # The IDE Compatibility version. -set(IDE_VERSION_DISPLAY "8.0.0-beta1") # The IDE display version. +set(IDE_VERSION "7.83.0") # The IDE version. +set(IDE_VERSION_COMPAT "7.83.0") # The IDE Compatibility version. +set(IDE_VERSION_DISPLAY "8.0.0-beta2") # The IDE display version. set(IDE_COPYRIGHT_YEAR "2022") # The IDE current copyright year. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. diff --git a/coin/instructions/common_environment.yaml b/coin/instructions/common_environment.yaml index 3b1faa00981..6141d447915 100644 --- a/coin/instructions/common_environment.yaml +++ b/coin/instructions/common_environment.yaml @@ -13,7 +13,7 @@ instructions: instructions: - type: EnvironmentVariable variableName: QTC_QT_BASE_URL - variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.3/6.3.0-final-released/Qt6.3.0" + variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.3/6.3.1-final-released/Qt6.3.1" - type: EnvironmentVariable variableName: QTC_QT_MODULES variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations" diff --git a/coin/instructions/provision.yaml b/coin/instructions/provision.yaml index 5d0431a273b..302103ec3f6 100644 --- a/coin/instructions/provision.yaml +++ b/coin/instructions/provision.yaml @@ -31,6 +31,15 @@ instructions: condition: property property: host.os in_values: [MacOS, Linux, Windows] + - type: ExecuteCommand + command: "pip3 install wget colorlog" + maxTimeInSeconds: 1200 + maxTimeBetweenOutput: 120 + userMessageOnFailure: "Failed to install Python packages, check logs." + enable_if: + condition: property + property: host.os + in_values: [MacOS, Linux] - type: ExecuteCommand command: "python3 -u {{.AgentWorkingDir}}/build/qtsdk/packaging-tools/install_qt.py --qt-path {{.AgentWorkingDir}}/build/qt_install_dir --temp-path {{.AgentWorkingDir}}/build/qt_temp --base-url {{.Env.QTC_QT_BASE_URL}} --base-url-postfix={{.Env.QTC_QT_POSTFIX}} --icu7z http://master.qt.io/development_releases/prebuilt/icu/prebuilt/56.1/icu-linux-g++-Rhel7.2-x64.7z {{.Env.QTC_QT_MODULES}}" executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution @@ -52,10 +61,10 @@ instructions: property: host.os equals_value: MacOS - type: ExecuteCommand - command: "pip.exe install pywin32" + command: "pip.exe install pywin32 wget colorlog" maxTimeInSeconds: 1200 maxTimeBetweenOutput: 120 - userMessageOnFailure: "Failed to install win32api, check logs." + userMessageOnFailure: "Failed to install Python packages, check logs." enable_if: condition: property property: host.os diff --git a/qbs/modules/qtc/qtc.qbs b/qbs/modules/qtc/qtc.qbs index 4d231e7063b..717ebe1d9fa 100644 --- a/qbs/modules/qtc/qtc.qbs +++ b/qbs/modules/qtc/qtc.qbs @@ -1,17 +1,20 @@ import qbs import qbs.Environment import qbs.FileInfo +import qbs.Utilities Module { - property string qtcreator_display_version: '8.0.0-beta1' + Depends { name: "cpp"; required: false } + + property string qtcreator_display_version: '8.0.0-beta2' property string ide_version_major: '7' - property string ide_version_minor: '82' + property string ide_version_minor: '83' property string ide_version_release: '0' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' + ide_version_release property string ide_compat_version_major: '7' - property string ide_compat_version_minor: '82' + property string ide_compat_version_minor: '83' property string ide_compat_version_release: '0' property string qtcreator_compat_version: ide_compat_version_major + '.' + ide_compat_version_minor + '.' + ide_compat_version_release @@ -92,4 +95,12 @@ Module { "QT_USE_QSTRINGBUILDER", ].concat(testsEnabled ? ["WITH_TESTS"] : []) .concat(qbs.toolchain.contains("msvc") ? ["_CRT_SECURE_NO_WARNINGS"] : []) + + Properties { + condition: cpp.present && qbs.toolchain.contains("msvc") && product.Qt + && Utilities.versionCompare(Qt.core.version, "6.3") >= 0 + && Utilities.versionCompare(cpp.compilerVersion, "19.10") >= 0 + && Utilities.versionCompare(qbs.version, "1.23") < 0 + cpp.cxxFlags: "/permissive-" + } } diff --git a/qtcreator_ide_branding.pri b/qtcreator_ide_branding.pri index bb1f7131f26..5f55cb9ead2 100644 --- a/qtcreator_ide_branding.pri +++ b/qtcreator_ide_branding.pri @@ -1,6 +1,6 @@ -QTCREATOR_VERSION = 7.82.0 -QTCREATOR_COMPAT_VERSION = 7.82.0 -QTCREATOR_DISPLAY_VERSION = 8.0.0-beta1 +QTCREATOR_VERSION = 7.83.0 +QTCREATOR_COMPAT_VERSION = 7.83.0 +QTCREATOR_DISPLAY_VERSION = 8.0.0-beta2 QTCREATOR_COPYRIGHT_YEAR = 2022 IDE_DISPLAY_NAME = Qt Creator diff --git a/scripts/deployqt.py b/scripts/deployqt.py index 33d216751fd..f02f41652fa 100755 --- a/scripts/deployqt.py +++ b/scripts/deployqt.py @@ -238,7 +238,7 @@ def deploy_clang(install_dir, llvm_install_dir, chrpath_bin): clanglibdirtarget = os.path.join(install_dir, 'bin', 'clang', 'lib') if not os.path.exists(clanglibdirtarget): os.makedirs(clanglibdirtarget) - for binary in ['clang', 'clang-cl', 'clangd', 'clang-tidy', 'clazy-standalone']: + for binary in ['clangd', 'clang-tidy', 'clazy-standalone']: binary_filepath = os.path.join(llvm_install_dir, 'bin', binary + '.exe') if os.path.exists(binary_filepath): deployinfo.append((binary_filepath, clangbindirtarget)) @@ -248,7 +248,7 @@ def deploy_clang(install_dir, llvm_install_dir, chrpath_bin): clangbinary_targetdir = os.path.join(install_dir, 'libexec', 'qtcreator', 'clang', 'bin') if not os.path.exists(clangbinary_targetdir): os.makedirs(clangbinary_targetdir) - for binary in ['clang', 'clangd', 'clang-tidy', 'clazy-standalone']: + for binary in ['clangd', 'clang-tidy', 'clazy-standalone']: binary_filepath = os.path.join(llvm_install_dir, 'bin', binary) if os.path.exists(binary_filepath): deployinfo.append((binary_filepath, clangbinary_targetdir)) @@ -262,7 +262,7 @@ def deploy_clang(install_dir, llvm_install_dir, chrpath_bin): if not os.path.exists(clanglibs_targetdir): os.makedirs(clanglibs_targetdir) # on RHEL ClazyPlugin is in lib64 - for lib_pattern in ['lib64/ClazyPlugin.so', 'lib/ClazyPlugin.so', 'lib/libclang-cpp.so*']: + for lib_pattern in ['lib64/ClazyPlugin.so', 'lib/ClazyPlugin.so']: for lib in glob(os.path.join(llvm_install_dir, lib_pattern)): deployinfo.append((lib, clanglibs_targetdir)) resourcetarget = os.path.join(install_dir, 'libexec', 'qtcreator', 'clang', 'lib', 'clang') diff --git a/scripts/deployqtHelper_mac.sh b/scripts/deployqtHelper_mac.sh index 8e6880f7d99..487cdfda656 100755 --- a/scripts/deployqtHelper_mac.sh +++ b/scripts/deployqtHelper_mac.sh @@ -111,21 +111,14 @@ fi # copy clang if needed if [ $LLVM_INSTALL_DIR ]; then - if [ "$LLVM_INSTALL_DIR"/lib/libclang-cpp.dylib -nt "$libexec_path"/clang/lib/libclang-cpp.dylib ]; then + if [ "$LLVM_INSTALL_DIR"/bin/clangd -nt "$libexec_path"/clang/bin/clangd ]; then echo "- Copying clang" mkdir -p "$app_path/Contents/Frameworks" || exit 1 # use recursive copy to make it copy symlinks as symlinks mkdir -p "$libexec_path/clang/bin" mkdir -p "$libexec_path/clang/lib" cp -Rf "$LLVM_INSTALL_DIR"/lib/clang "$libexec_path/clang/lib/" || exit 1 - cp -Rf "$LLVM_INSTALL_DIR"/lib/libclang-cpp.dylib "$libexec_path/clang/lib/" || exit 1 cp -Rf "$LLVM_INSTALL_DIR"/lib/ClazyPlugin.dylib "$libexec_path/clang/lib/" || exit 1 - clangsource="$LLVM_INSTALL_DIR"/bin/clang - clanglinktarget="$(readlink "$clangsource")" - cp -Rf "$clangsource" "$libexec_path/clang/bin/" || exit 1 - if [ $clanglinktarget ]; then - cp -Rf "$(dirname "$clangsource")/$clanglinktarget" "$libexec_path/clang/bin/$clanglinktarget" || exit 1 - fi clangdsource="$LLVM_INSTALL_DIR"/bin/clangd cp -Rf "$clangdsource" "$libexec_path/clang/bin/" || exit 1 clangtidysource="$LLVM_INSTALL_DIR"/bin/clang-tidy diff --git a/share/qtcreator/debugger/dumper.py b/share/qtcreator/debugger/dumper.py index 7a54f7676f6..3f3acbe46da 100644 --- a/share/qtcreator/debugger/dumper.py +++ b/share/qtcreator/debugger/dumper.py @@ -29,7 +29,6 @@ import collections import glob import struct import sys -import base64 import re import time import inspect @@ -45,6 +44,14 @@ except: "Native combined debugging might not work.") pass +try: + # That fails on some QNX via Windows installations + import base64 + def hexencode_(s): + return base64.b16encode(s).decode('utf8') +except: + def hexencode_(s): + return ''.join(["%x" % c for c in s]) if sys.version_info[0] >= 3: toInteger = int @@ -550,7 +557,7 @@ class DumperBase(): return s.encode('hex') if isinstance(s, str): s = s.encode('utf8') - return base64.b16encode(s).decode('utf8') + return hexencode_(s) def isQt3Support(self): # assume no Qt 3 support by default diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json index 7a032fc0f11..fecabd09428 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/empty/wizard.json @@ -33,7 +33,11 @@ "name": "PySideVersion", "trDisplayName": "PySide version:", "type": "ComboBox", - "data": { "items": [ "PySide2", "PySide6" ] } + "data": + { + "index": 1, + "items": [ "PySide2", "PySide6" ] + } } ] }, diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json index 1e19a607f71..d9f575ecd9b 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/mainwindow/wizard.json @@ -34,7 +34,11 @@ "name": "PySideVersion", "trDisplayName": "PySide version:", "type": "ComboBox", - "data": { "items": [ "PySide2", "PySide6" ] } + "data": + { + "index": 1, + "items": [ "PySide2", "PySide6" ] + } }, { "name": "Class", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json index 68051e52f78..7ab73b917f4 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/qtquickapplication/wizard.json @@ -39,7 +39,7 @@ "type": "ComboBox", "data": { - "index": 2, + "index": 0, "items": [ { diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json index 6b2bd45565f..b9c96c97886 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget/wizard.json @@ -34,7 +34,11 @@ "name": "PySideVersion", "trDisplayName": "PySide version:", "type": "ComboBox", - "data": { "items": [ "PySide2", "PySide6" ] } + "data": + { + "index": 1, + "items": [ "PySide2", "PySide6" ] + } }, { "name": "Class", diff --git a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/wizard.json b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/wizard.json index 1a2bcec74b4..91572c2bdd2 100644 --- a/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtforpythonapplication/widget_gen/wizard.json @@ -34,7 +34,11 @@ "name": "PySideVersion", "trDisplayName": "PySide version:", "type": "ComboBox", - "data": { "items": [ "PySide2", "PySide6" ] } + "data": + { + "index": 1, + "items": [ "PySide2", "PySide6" ] + } }, { "name": "Class", diff --git a/src/libs/languageserverprotocol/completion.cpp b/src/libs/languageserverprotocol/completion.cpp index 9f04338e87e..10d38c71178 100644 --- a/src/libs/languageserverprotocol/completion.cpp +++ b/src/libs/languageserverprotocol/completion.cpp @@ -49,6 +49,16 @@ Utils::optional CompletionItem::insertTextForm return Utils::nullopt; } +Utils::optional> CompletionItem::tags() const +{ + if (const auto value = optionalValue(tagsKey)) { + QList tags; + for (auto it = value->cbegin(); it != value->cend(); ++it) + tags << static_cast(it->toInt()); + return tags; + } + return {}; +} CompletionItemResolveRequest::CompletionItemResolveRequest(const CompletionItem ¶ms) : Request(methodName, params) diff --git a/src/libs/languageserverprotocol/completion.h b/src/libs/languageserverprotocol/completion.h index ab5e43ac220..b635e121e42 100644 --- a/src/libs/languageserverprotocol/completion.h +++ b/src/libs/languageserverprotocol/completion.h @@ -214,6 +214,27 @@ public: void setData(const QJsonValue &data) { insert(dataKey, data); } void clearData() { remove(dataKey); } + /** + * Completion item tags are extra annotations that tweak the rendering of a + * completion item. + * @since 3.15.0 + */ + enum CompletionItemTag { + Deprecated = 1, + }; + + /** + * Tags for this completion item. + * @since 3.15.0 + */ + Utils::optional> tags() const; + + /** + * Indicates if this item is deprecated. + * @deprecated Use `tags` instead if supported. + */ + Utils::optional deprecated() const { return optionalValue(deprecatedKey); } + bool isValid() const override { return contains(labelKey); } }; diff --git a/src/libs/languageserverprotocol/jsonkeys.h b/src/libs/languageserverprotocol/jsonkeys.h index f5c10a0b5d6..3c520ebad93 100644 --- a/src/libs/languageserverprotocol/jsonkeys.h +++ b/src/libs/languageserverprotocol/jsonkeys.h @@ -209,6 +209,7 @@ constexpr char symbolKindKey[] = "symbolKind"; constexpr char syncKindKey[] = "syncKind"; constexpr char synchronizationKey[] = "synchronization"; constexpr char tabSizeKey[] = "tabSize"; +constexpr char tagsKey[] = "tags"; constexpr char targetKey[] = "target"; constexpr char textDocumentKey[] = "textDocument"; constexpr char textDocumentSyncKey[] = "textDocumentSync"; diff --git a/src/libs/qmljs/qmljsfindexportedcpptypes.cpp b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp index 40358b6c954..72a4cfad511 100644 --- a/src/libs/qmljs/qmljsfindexportedcpptypes.cpp +++ b/src/libs/qmljs/qmljsfindexportedcpptypes.cpp @@ -334,7 +334,7 @@ protected: _doc->fileName(), line, column, QmlJS::FindExportedCppTypes::tr( - "The module URI cannot be determined by static analysis. The type will be available\n" + "The module URI cannot be determined by static analysis. The type will not be available\n" "globally in the QML editor. You can add a \"// @uri My.Module.Uri\" annotation to let\n" "the QML editor know about a likely URI.")); } diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 74526295813..9412406fdc4 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -2378,8 +2378,12 @@ const Value *TypeScope::lookupMember(const QString &name, const Context *context continue; if (const Value *v = import->lookupMember(name, context, foundInObject)) { - i.used = true; - return v; + // FIXME if we have multiple non-aliased imports containing this object we'd have to + // disambiguate (and inform the user) about this issue + if (info.as().isEmpty()) { + i.used = true; + return v; + } } } if (foundInObject) diff --git a/src/libs/qmljs/qmljslink.cpp b/src/libs/qmljs/qmljslink.cpp index fe3301db933..df881a09ab4 100644 --- a/src/libs/qmljs/qmljslink.cpp +++ b/src/libs/qmljs/qmljslink.cpp @@ -465,7 +465,8 @@ Import LinkPrivate::importNonFile(const Document::Ptr &doc, const ImportInfo &im "For Qbs projects, declare and set a qmlImportPaths property in your product " "to add import paths.\n" "For qmlproject projects, use the importPaths property to add import paths.\n" - "For CMake projects, make sure QML_IMPORT_PATH variable is in CMakeCache.txt.\n") + "For CMake projects, make sure QML_IMPORT_PATH variable is in CMakeCache.txt.\n" + "For qmlRegister... calls, make sure that you define the Module URI as a string literal.\n") .arg(importInfo.name(), m_importPaths.join(QLatin1Char('\n')))); } diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp index 5f649931ad3..444d429a4bc 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.cpp +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.cpp @@ -446,6 +446,20 @@ bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1, } +static QList generatedQrc(QStringList applicationDirectories) +{ + QList res; + for (const QString &pathStr : applicationDirectories) { + Utils::FilePath path = Utils::FilePath::fromString(pathStr); + Utils::FilePath generatedQrcDir = path.pathAppended(".rcc"); + if (generatedQrcDir.isReadableDir()) { + for (const Utils::FilePath & qrcPath: generatedQrcDir.dirEntries(FileFilter(QStringList({QStringLiteral(u"*.qrc")}), QDir::Files))) + res.append(qrcPath.canonicalPath()); + } + } + return res; +} + void ModelManagerInterface::iterateQrcFiles( ProjectExplorer::Project *project, QrcResourceSelector resources, const std::function &callback) @@ -461,18 +475,21 @@ void ModelManagerInterface::iterateQrcFiles( Utils::sort(pInfos, &pInfoLessThanAll); } - QSet pathsChecked; + QSet pathsChecked; for (const ModelManagerInterface::ProjectInfo &pInfo : qAsConst(pInfos)) { QStringList qrcFilePaths; if (resources == ActiveQrcResources) qrcFilePaths = pInfo.activeResourceFiles; else qrcFilePaths = pInfo.allResourceFiles; - for (const QString &qrcFilePath : qAsConst(qrcFilePaths)) { + for (const Utils::FilePath &p : generatedQrc(pInfo.applicationDirectories)) + qrcFilePaths.append(p.toString()); + for (const QString &qrcFilePathStr : qAsConst(qrcFilePaths)) { + auto qrcFilePath = Utils::FilePath::fromString(qrcFilePathStr); if (pathsChecked.contains(qrcFilePath)) continue; pathsChecked.insert(qrcFilePath); - QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath); + QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath.toString()); if (qrcFile.isNull()) continue; callback(qrcFile); @@ -589,6 +606,8 @@ void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectE m_qrcContents = pinfo.resourceFileContents; for (const QString &newQrc : qAsConst(pinfo.allResourceFiles)) m_qrcCache.addPath(newQrc, m_qrcContents.value(newQrc)); + for (const Utils::FilePath &newQrc : generatedQrc(pinfo.applicationDirectories)) + m_qrcCache.addPath(newQrc.toString(), m_qrcContents.value(newQrc.toString())); for (const QString &oldQrc : qAsConst(oldInfo.allResourceFiles)) m_qrcCache.removePath(oldQrc); @@ -1180,6 +1199,29 @@ void ModelManagerInterface::maybeScan(const PathsAndLanguages &importPaths) } } +static QList minimalPrefixPaths(const QStringList &paths) +{ + QList sortedPaths; + // find minimal prefix, ensure '/' at end + for (const QString &pathStr : qAsConst(paths)) { + Utils::FilePath path = Utils::FilePath::fromString(pathStr); + if (!path.endsWith("/")) + path.setPath(path.path() + "/"); + if (path.path().length() > 1) + sortedPaths.append(path); + } + std::sort(sortedPaths.begin(), sortedPaths.end()); + QList res; + QString lastPrefix; + for (auto it = sortedPaths.begin(); it != sortedPaths.end(); ++it) { + if (lastPrefix.isEmpty() || !it->startsWith(lastPrefix)) { + lastPrefix = it->path(); + res.append(*it); + } + } + return res; +} + void ModelManagerInterface::updateImportPaths() { if (m_indexerDisabled) @@ -1243,6 +1285,7 @@ void ModelManagerInterface::updateImportPaths() m_allImportPaths = allImportPaths; m_activeBundles = activeBundles; m_extendedBundles = extendedBundles; + m_applicationPaths = minimalPrefixPaths(allApplicationDirectories); } @@ -1253,10 +1296,13 @@ void ModelManagerInterface::updateImportPaths() QSet newLibraries; for (const Document::Ptr &doc : qAsConst(snapshot)) findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries); - for (const QString &path : qAsConst(allApplicationDirectories)) { - allImportPaths.maybeInsert(FilePath::fromString(path), Dialect::Qml); - findNewQmlApplicationInPath(FilePath::fromString(path), snapshot, this, &newLibraries); + for (const QString &pathStr : qAsConst(allApplicationDirectories)) { + Utils::FilePath path = Utils::FilePath::fromString(pathStr); + allImportPaths.maybeInsert(path, Dialect::Qml); + findNewQmlApplicationInPath(path, snapshot, this, &newLibraries); } + for (const Utils::FilePath &qrcPath : generatedQrc(allApplicationDirectories)) + updateQrcFile(qrcPath.toString()); updateSourceFiles(importedFiles, true); @@ -1668,4 +1714,47 @@ void ModelManagerInterface::resetCodeModel() updateImportPaths(); } +Utils::FilePath ModelManagerInterface::fileToSource(const Utils::FilePath &path) +{ + if (!path.scheme().isEmpty()) + return path; + for (const Utils::FilePath &p : m_applicationPaths) { + if (!p.isEmpty() && path.startsWith(p.path())) { + // if it is an applicationPath (i.e. in the build directory) + // try to use the path from the build dir as resource path + // and recover the path of the corresponding source file + QString reducedPath = path.path().mid(p.path().size()); + QString reversePath(reducedPath); + std::reverse(reversePath.begin(), reversePath.end()); + if (!reversePath.endsWith('/')) + reversePath.append('/'); + QrcParser::MatchResult res; + iterateQrcFiles(nullptr, + QrcResourceSelector::AllQrcResources, + [&](const QrcParser::ConstPtr &qrcFile) { + if (!qrcFile) + return; + QrcParser::MatchResult matchNow = qrcFile->longestReverseMatches( + reversePath); + + if (matchNow.matchDepth < res.matchDepth) + return; + if (matchNow.matchDepth == res.matchDepth) { + res.reversedPaths += matchNow.reversedPaths; + res.sourceFiles += matchNow.sourceFiles; + } else { + res = matchNow; + } + }); + std::sort(res.sourceFiles.begin(), res.sourceFiles.end()); + if (!res.sourceFiles.isEmpty()) { + return res.sourceFiles.first(); + } + qCWarning(qmljsLog) << "Could not find source file for file" << path + << "in application path" << p; + } + } + return path; +} + } // namespace QmlJS diff --git a/src/libs/qmljs/qmljsmodelmanagerinterface.h b/src/libs/qmljs/qmljsmodelmanagerinterface.h index 5a4f711a1be..4ed02c2c96d 100644 --- a/src/libs/qmljs/qmljsmodelmanagerinterface.h +++ b/src/libs/qmljs/qmljsmodelmanagerinterface.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -149,6 +150,7 @@ public: ProjectExplorer::Project *project = nullptr, bool addDirs = false, QrcResourceSelector resources = AllQrcResources); + Utils::FilePath fileToSource(const Utils::FilePath &file); QList projectInfos() const; bool containsProject(ProjectExplorer::Project *project) const; @@ -254,6 +256,7 @@ private: QmlJS::Snapshot m_validSnapshot; QmlJS::Snapshot m_newestSnapshot; PathsAndLanguages m_allImportPaths; + QList m_applicationPaths; QStringList m_defaultImportPaths; QmlJS::QmlLanguageBundles m_activeBundles; QmlJS::QmlLanguageBundles m_extendedBundles; diff --git a/src/libs/qmljs/qmljsplugindumper.cpp b/src/libs/qmljs/qmljsplugindumper.cpp index e5e3a952c05..56d444f9d9e 100644 --- a/src/libs/qmljs/qmljsplugindumper.cpp +++ b/src/libs/qmljs/qmljsplugindumper.cpp @@ -264,13 +264,20 @@ void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process) return; const Snapshot snapshot = m_modelManager->snapshot(); LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath); - bool privatePlugin = libraryPath.endsWith(QLatin1String("private")); + const bool privatePlugin = libraryPath.endsWith(QLatin1String("private")); - if (process->exitCode() != 0) { + if (process->exitCode() || process->error() != QProcess::UnknownError) { const QString errorMessages = qmlPluginDumpErrorMessage(process); if (!privatePlugin) ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages)); - libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, qmldumpFailedMessage(libraryPath, errorMessages)); + libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, + qmldumpFailedMessage(libraryPath, errorMessages)); + + if (process->error() != QProcess::UnknownError) { + libraryInfo.updateFingerprint(); + m_modelManager->updateLibraryInfo(libraryPath, libraryInfo); + return; + } const QByteArray output = process->readAllStandardOutput(); @@ -324,23 +331,6 @@ void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process) } } -void PluginDumper::qmlPluginTypeDumpError(QtcProcess *process) -{ - process->deleteLater(); - - const FilePath libraryPath = m_runningQmldumps.take(process); - if (libraryPath.isEmpty()) - return; - const QString errorMessages = qmlPluginDumpErrorMessage(process); - const Snapshot snapshot = m_modelManager->snapshot(); - LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath); - if (!libraryPath.path().endsWith(QLatin1String("private"), Qt::CaseInsensitive)) - ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages)); - libraryInfo.setPluginTypeInfoStatus(LibraryInfo::DumpError, qmldumpFailedMessage(libraryPath, errorMessages)); - libraryInfo.updateFingerprint(); - m_modelManager->updateLibraryInfo(libraryPath, libraryInfo); -} - void PluginDumper::pluginChanged(const QString &pluginLibrary) { const int pluginIndex = m_libraryToPluginIndex.value(pluginLibrary, -1); @@ -628,8 +618,7 @@ void PluginDumper::runQmlDump(const ModelManagerInterface::ProjectInfo &info, process->setEnvironment(info.qmlDumpEnvironment); process->setWorkingDirectory(importPath); process->setCommand({info.qmlDumpPath, arguments}); - connect(process, &QtcProcess::finished, this, [this, process] { qmlPluginTypeDumpDone(process); }); - connect(process, &QtcProcess::errorOccurred, this, [this, process] { qmlPluginTypeDumpError(process); }); + connect(process, &QtcProcess::done, this, [this, process] { qmlPluginTypeDumpDone(process); }); process->start(); m_runningQmldumps.insert(process, importPath); } diff --git a/src/libs/qmljs/qmljsplugindumper.h b/src/libs/qmljs/qmljsplugindumper.h index 7b4e035013e..7d289a4258f 100644 --- a/src/libs/qmljs/qmljsplugindumper.h +++ b/src/libs/qmljs/qmljsplugindumper.h @@ -60,7 +60,6 @@ private: const QString &importUri, const QString &importVersion); Q_INVOKABLE void dumpAllPlugins(); void qmlPluginTypeDumpDone(Utils::QtcProcess *process); - void qmlPluginTypeDumpError(Utils::QtcProcess *process); void pluginChanged(const QString &pluginLibrary); private: diff --git a/src/libs/qtcreatorcdbext/CMakeLists.txt b/src/libs/qtcreatorcdbext/CMakeLists.txt index 334d226af4d..ba6508c43e0 100644 --- a/src/libs/qtcreatorcdbext/CMakeLists.txt +++ b/src/libs/qtcreatorcdbext/CMakeLists.txt @@ -20,9 +20,13 @@ endif() find_library(DbgEngLib dbgeng) -set(ArchSuffix 32) +set(ArchSuffix "32") if (CMAKE_SIZEOF_VOID_P EQUAL 8) - set(ArchSuffix 64) + set(ArchSuffix "64") +endif() + +if (MSVC_CXX_ARCHITECTURE_ID MATCHES "^ARM") + set(ArchSuffix "arm${ArchSuffix}") endif() add_qtc_library(qtcreatorcdbext SHARED diff --git a/src/libs/utils/aspects.cpp b/src/libs/utils/aspects.cpp index 998d9fa5cc1..79f6428a4a2 100644 --- a/src/libs/utils/aspects.cpp +++ b/src/libs/utils/aspects.cpp @@ -1138,6 +1138,9 @@ void StringAspect::addToLayout(LayoutBuilder &builder) &FancyLineEdit::textEdited, this, &StringAspect::setValue); + connect(d->m_lineEditDisplay, &FancyLineEdit::editingFinished, this, [this] { + setValue(d->m_lineEditDisplay->text()); + }); } } if (d->m_useResetButton) { @@ -2442,6 +2445,10 @@ void AspectContainerData::append(const BaseAspect::Data::Ptr &data) m_data.append(data); } +// BaseAspect::Data + +BaseAspect::Data::~Data() = default; + void BaseAspect::Data::Ptr::operator=(const Ptr &other) { if (this == &other) diff --git a/src/libs/utils/aspects.h b/src/libs/utils/aspects.h index bade3c9495f..bb39a398cb1 100644 --- a/src/libs/utils/aspects.h +++ b/src/libs/utils/aspects.h @@ -145,7 +145,7 @@ public: // The (unique) address of the "owning" aspect's meta object is used as identifier. using ClassId = const void *; - virtual ~Data() = default; + virtual ~Data(); Id id() const { return m_id; } ClassId classId() const { return m_classId; } diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index c1030fd5e78..a23ba678dcb 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -50,7 +50,7 @@ FilePath BuildableHelperLibrary::qtChooserToQmakePath(const FilePath &qtChooser) proc.runBlocking(); if (proc.result() != ProcessResult::FinishedWithSuccess) return {}; - const QString output = proc.stdOut(); + const QString output = proc.cleanedStdOut(); int pos = output.indexOf(toolDir); if (pos == -1) return {}; diff --git a/src/libs/utils/deviceshell.cpp b/src/libs/utils/deviceshell.cpp index 807ac2c4bd5..7256b9cb3a9 100644 --- a/src/libs/utils/deviceshell.cpp +++ b/src/libs/utils/deviceshell.cpp @@ -277,8 +277,8 @@ void DeviceShell::startupFailed(const CommandLine &cmdLine) bool DeviceShell::start() { m_shellProcess = new QtcProcess(); - connect(m_shellProcess, &QtcProcess::done, this, [this] { emit done(); }); - connect(m_shellProcess, &QtcProcess::errorOccurred, this, &DeviceShell::errorOccurred); + connect(m_shellProcess, &QtcProcess::done, m_shellProcess, + [this] { emit done(m_shellProcess->resultData()); }); connect(m_shellProcess, &QObject::destroyed, this, [this] { m_shellProcess = nullptr; }); connect(&m_thread, &QThread::finished, m_shellProcess, [this] { closeShellProcess(); }); diff --git a/src/libs/utils/deviceshell.h b/src/libs/utils/deviceshell.h index 8def78f6d3c..d25746ddf12 100644 --- a/src/libs/utils/deviceshell.h +++ b/src/libs/utils/deviceshell.h @@ -36,6 +36,7 @@ namespace Utils { class CommandLine; +class ProcessResultData; class QtcProcess; class DeviceShellImpl; @@ -69,8 +70,7 @@ public: State state() const; signals: - void done(); - void errorOccurred(QProcess::ProcessError error); + void done(const ProcessResultData &resultData); protected: virtual void startupFailed(const CommandLine &cmdLine); diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 14436bdc1d1..cbde3ddd092 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -945,8 +945,30 @@ QString FilePath::displayName(const QString &args) const .arg(m_data, args, deviceName); } -/// Constructs a FilePath from \a filename -/// \a filename is not checked for validity. +/*! + Constructs a FilePath from \a filepath + + \a filepath is not checked for validity. It can be given in the following forms: + + \list + \li /some/absolute/local/path + \li some/relative/path + \li scheme://host/absolute/path + \li scheme://host/./relative/path \note the ./ is verbatim part of the path + \endlist + + Some decoding happens when parsing the \a filepath + A sequence %25 present in the host part is replaced by % in the host name, + a sequence %2f present in the host part is replaced by / in the host name. + + The path part might consist of several parts separated by /, independent + of the platform or file system. + + To create FilePath objects from strings possibly containing backslashes as + path separator, use \c fromUserInput. + + \sa toString, fromUserInput + */ FilePath FilePath::fromString(const QString &filepath) { FilePath fn; @@ -1285,9 +1307,16 @@ FilePath FilePath::searchInDirectories(const FilePaths &dirs) const return Environment::systemEnvironment().searchInDirectories(path(), dirs); } -FilePath FilePath::searchInPath(const QList &additionalDirs) const +FilePath FilePath::searchInPath(const FilePaths &additionalDirs, PathAmending amending) const { - return searchInDirectories(deviceEnvironment().path() + additionalDirs); + FilePaths directories = deviceEnvironment().path(); + if (!additionalDirs.isEmpty()) { + if (amending == AppendToPath) + directories.append(additionalDirs); + else + directories = additionalDirs + directories; + } + return searchInDirectories(directories); } Environment FilePath::deviceEnvironment() const diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index faf61ee66fb..4b589389b4d 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -164,13 +164,16 @@ public: [[nodiscard]] FilePath relativeChildPath(const FilePath &parent) const; [[nodiscard]] FilePath relativePath(const FilePath &anchor) const; [[nodiscard]] FilePath searchInDirectories(const QList &dirs) const; - [[nodiscard]] FilePath searchInPath(const QList &additionalDirs = {}) const; [[nodiscard]] Environment deviceEnvironment() const; [[nodiscard]] FilePath onDevice(const FilePath &deviceTemplate) const; [[nodiscard]] FilePath withNewPath(const QString &newPath) const; void iterateDirectory(const std::function &callBack, const FileFilter &filter) const; + enum PathAmending { AppendToPath, PrependToPath }; + [[nodiscard]] FilePath searchInPath(const QList &additionalDirs = {}, + PathAmending = AppendToPath) const; + // makes sure that capitalization of directories is canonical // on Windows and macOS. This is rarely needed. [[nodiscard]] FilePath normalizedPathName() const; diff --git a/src/libs/utils/hostosinfo.cpp b/src/libs/utils/hostosinfo.cpp index 48518f8fc1a..79f042e0f05 100644 --- a/src/libs/utils/hostosinfo.cpp +++ b/src/libs/utils/hostosinfo.cpp @@ -31,6 +31,10 @@ #include #endif +#ifdef Q_OS_LINUX +#include +#endif + #ifdef Q_OS_WIN #include #endif @@ -65,8 +69,9 @@ HostOsInfo::HostArchitecture HostOsInfo::hostArchitecture() case PROCESSOR_ARCHITECTURE_IA64: return HostOsInfo::HostArchitectureItanium; case PROCESSOR_ARCHITECTURE_ARM: - case PROCESSOR_ARCHITECTURE_ARM64: return HostOsInfo::HostArchitectureArm; + case PROCESSOR_ARCHITECTURE_ARM64: + return HostOsInfo::HostArchitectureArm64; default: return HostOsInfo::HostArchitectureUnknown; } @@ -110,3 +115,27 @@ bool HostOsInfo::canCreateOpenGLContext(QString *errorMessage) return canCreate; #endif } + +optional HostOsInfo::totalMemoryInstalledInBytes() +{ +#ifdef Q_OS_LINUX + struct sysinfo info; + if (sysinfo(&info) == -1) + return {}; + return info.totalram; +#elif defined(Q_OS_WIN) + MEMORYSTATUSEX statex; + statex.dwLength = sizeof statex; + if (!GlobalMemoryStatusEx(&statex)) + return {}; + return statex.ullTotalPhys; +#elif defined(Q_OS_MACOS) + int mib[] = {CTL_HW, HW_MEMSIZE}; + int64_t ram; + size_t length = sizeof(int64_t); + if (sysctl(mib, 2, &ram, &length, nullptr, 0) == -1) + return {}; + return ram; +#endif + return {}; +} diff --git a/src/libs/utils/hostosinfo.h b/src/libs/utils/hostosinfo.h index 694146e3459..9823c7e6f23 100644 --- a/src/libs/utils/hostosinfo.h +++ b/src/libs/utils/hostosinfo.h @@ -27,6 +27,7 @@ #include "utils_global.h" +#include "optional.h" #include "osspecificaspects.h" QT_BEGIN_NAMESPACE @@ -60,7 +61,7 @@ public: } enum HostArchitecture { HostArchitectureX86, HostArchitectureAMD64, HostArchitectureItanium, - HostArchitectureArm, HostArchitectureUnknown }; + HostArchitectureArm, HostArchitectureArm64, HostArchitectureUnknown }; static HostArchitecture hostArchitecture(); static constexpr bool isWindowsHost() { return hostOs() == OsTypeWindows; } @@ -104,6 +105,8 @@ public: static bool canCreateOpenGLContext(QString *errorMessage); + static optional totalMemoryInstalledInBytes(); + private: static Qt::CaseSensitivity m_overrideFileNameCaseSensitivity; static bool m_useOverrideFileNameCaseSensitivity; diff --git a/src/libs/utils/pathchooser.cpp b/src/libs/utils/pathchooser.cpp index 27d08acb803..7a31cf8318d 100644 --- a/src/libs/utils/pathchooser.cpp +++ b/src/libs/utils/pathchooser.cpp @@ -178,7 +178,7 @@ class PathChooserPrivate public: PathChooserPrivate(); - FilePath expandedPath(const QString &path) const; + FilePath expandedPath(const FilePath &path) const; QHBoxLayout *m_hLayout = nullptr; FancyLineEdit *m_lineEdit = nullptr; @@ -202,12 +202,12 @@ PathChooserPrivate::PathChooserPrivate() { } -FilePath PathChooserPrivate::expandedPath(const QString &input) const +FilePath PathChooserPrivate::expandedPath(const FilePath &input) const { if (input.isEmpty()) return {}; - FilePath path = FilePath::fromUserInput(input); + FilePath path = input; Environment env = path.deviceEnvironment(); m_environmentChange.applyToEnvironment(env); @@ -353,7 +353,7 @@ FilePath PathChooser::rawFilePath() const FilePath PathChooser::filePath() const { - return d->expandedPath(rawFilePath().toString()); + return d->expandedPath(rawFilePath()); } FilePath PathChooser::absoluteFilePath() const @@ -529,11 +529,11 @@ FancyLineEdit::ValidationFunction PathChooser::defaultValidationFunction() const bool PathChooser::validatePath(FancyLineEdit *edit, QString *errorMessage) const { - QString path = edit->text(); + QString input = edit->text(); - if (path.isEmpty()) { + if (input.isEmpty()) { if (!d->m_defaultValue.isEmpty()) { - path = d->m_defaultValue; + input = d->m_defaultValue; } else { if (errorMessage) *errorMessage = tr("The path must not be empty."); @@ -541,10 +541,10 @@ bool PathChooser::validatePath(FancyLineEdit *edit, QString *errorMessage) const } } - const FilePath filePath = d->expandedPath(path); + const FilePath filePath = d->expandedPath(FilePath::fromUserInput(input)); if (filePath.isEmpty()) { if (errorMessage) - *errorMessage = tr("The path \"%1\" expanded to an empty string.").arg(QDir::toNativeSeparators(path)); + *errorMessage = tr("The path \"%1\" expanded to an empty string.").arg(input); return false; } diff --git a/src/libs/utils/qrcparser.cpp b/src/libs/utils/qrcparser.cpp index 24846ebf63b..58935f12100 100644 --- a/src/libs/utils/qrcparser.cpp +++ b/src/libs/utils/qrcparser.cpp @@ -57,6 +57,7 @@ public: const QLocale *locale = nullptr) const; void collectResourceFilesForSourceFile(const QString &sourceFile, QStringList *res, const QLocale *locale = nullptr) const; + QrcParser::MatchResult longestReverseMatches(const QString &) const; QStringList errorMessages() const; QStringList languages() const; @@ -65,6 +66,7 @@ private: const QStringList allUiLanguages(const QLocale *locale) const; SMap m_resources; + SMap m_reverseResources; SMap m_files; QStringList m_languages; QStringList m_errorMessages; @@ -207,6 +209,11 @@ void QrcParser::collectFilesAtPath(const QString &path, QStringList *res, const d->collectFilesAtPath(path, res, locale); } +QrcParser::MatchResult QrcParser::longestReverseMatches(const QString &p) const +{ + return d->longestReverseMatches(p); +} + /*! Returns \c true if \a path is a non-empty directory and matches \a locale. @@ -414,8 +421,14 @@ bool QrcParserPrivate::parseFile(const QString &path, const QString &contents) else accessPath = language + prefix + fileName; QStringList &resources = m_resources[accessPath]; - if (!resources.contains(filePath)) + if (!resources.contains(filePath)) { resources.append(filePath); + QString reversePath(accessPath); + std::reverse(reversePath.begin(), reversePath.end()); + if (!reversePath.endsWith('/')) + reversePath.append('/'); + m_reverseResources[reversePath].append(filePath); + } QStringList &files = m_files[filePath]; if (!files.contains(accessPath)) files.append(accessPath); @@ -517,6 +530,37 @@ void QrcParserPrivate::collectResourceFilesForSourceFile(const QString &sourceFi } } +QrcParser::MatchResult QrcParserPrivate::longestReverseMatches(const QString &reversePath) const +{ + QrcParser::MatchResult res; + if (reversePath.length() == 1) + return res; + auto lastMatch = m_reverseResources.end(); + qsizetype matchedUntil = 0; + for (qsizetype i = 1, j = 0; i < reversePath.size(); i = j + 1) { + j = reversePath.indexOf(u'/', i); + if (j == -1) + j = reversePath.size() - 1; + auto match = m_reverseResources.lowerBound(reversePath.mid(0, j + 1)); + QString pNow = reversePath.left(j + 1); + if (match == m_reverseResources.end() || match.key().left(j + 1) != pNow) + break; + ++res.matchDepth; + matchedUntil = j + 1; + lastMatch = match; + } + res.reversedPaths.clear(); + res.sourceFiles.clear(); + for (auto it = lastMatch; it != m_reverseResources.end() + && it.key().left(matchedUntil) == reversePath.left(matchedUntil); + ++it) { + res.reversedPaths.append(it.key()); + for (const QString &filePath : it.value()) + res.sourceFiles.append(Utils::FilePath::fromString(filePath)); + } + return res; +} + QStringList QrcParserPrivate::errorMessages() const { return m_errorMessages; diff --git a/src/libs/utils/qrcparser.h b/src/libs/utils/qrcparser.h index 665df445484..3027076a97e 100644 --- a/src/libs/utils/qrcparser.h +++ b/src/libs/utils/qrcparser.h @@ -26,6 +26,7 @@ #pragma once #include "utils_global.h" +#include "utils/filepath.h" #include #include @@ -47,12 +48,20 @@ class QrcCachePrivate; class QTCREATOR_UTILS_EXPORT QrcParser { public: + struct MatchResult + { + int matchDepth = {}; + QStringList reversedPaths; + QList sourceFiles; + }; + typedef QSharedPointer Ptr; typedef QSharedPointer ConstPtr; ~QrcParser(); bool parseFile(const QString &path, const QString &contents); QString firstFileAtPath(const QString &path, const QLocale &locale) const; void collectFilesAtPath(const QString &path, QStringList *res, const QLocale *locale = nullptr) const; + MatchResult longestReverseMatches(const QString &) const; bool hasDirAtPath(const QString &path, const QLocale *locale = nullptr) const; void collectFilesInPath(const QString &path, QMap *res, bool addDirs = false, const QLocale *locale = nullptr) const; diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 925038086f4..18283cc3a08 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -1034,7 +1034,7 @@ QtcProcess::QtcProcess(QObject *parent) Q_UNUSED(qProcessProcessErrorMeta) if (processLog().isDebugEnabled()) { - connect(this, &QtcProcess::finished, [this] { + connect(this, &QtcProcess::done, [this] { if (!d->m_process.get()) return; const QVariant n = d->m_process.get()->property(QTC_PROCESS_NUMBER); @@ -1051,17 +1051,17 @@ QtcProcess::QtcProcess(QObject *parent) qCDebug(processLog).nospace() << "Process " << number << " finished: " << "result=" << int(result()) << ", ex=" << exitCode() - << ", " << stdOut().size() << " bytes stdout: " - << stdOut().left(20) - << ", " << stdErr().size() << " bytes stderr: " - << stdErr().left(1000) + << ", " << cleanedStdOut().size() << " bytes stdout: " + << cleanedStdOut().left(20) + << ", " << cleanedStdErr().size() << " bytes stderr: " + << cleanedStdErr().left(1000) << ", " << msElapsed << " ms elapsed"; - if (processStdoutLog().isDebugEnabled() && !stdOut().isEmpty()) + if (processStdoutLog().isDebugEnabled() && !cleanedStdOut().isEmpty()) qCDebug(processStdoutLog).nospace() - << "Process " << number << " sdout: " << stdOut(); - if (processStderrLog().isDebugEnabled() && !stdErr().isEmpty()) + << "Process " << number << " sdout: " << cleanedStdOut(); + if (processStderrLog().isDebugEnabled() && !cleanedStdErr().isEmpty()) qCDebug(processStderrLog).nospace() - << "Process " << number << " stderr: " << stdErr(); + << "Process " << number << " stderr: " << cleanedStdErr(); }); } } @@ -1617,12 +1617,6 @@ void QtcProcess::stop() d->m_killTimer.start(d->m_process->m_setup.m_reaperTimeout); } -QString QtcProcess::locateBinary(const QString &binary) -{ - const QByteArray path = qgetenv("PATH"); - return locateBinary(QString::fromLocal8Bit(path), binary); -} - /*! \class Utils::SynchronousProcess @@ -1691,8 +1685,8 @@ QString QtcProcess::allOutput() const { QTC_CHECK(d->m_stdOut.keepRawData); QTC_CHECK(d->m_stdErr.keepRawData); - const QString out = stdOut(); - const QString err = stdErr(); + const QString out = cleanedStdOut(); + const QString err = cleanedStdErr(); if (!out.isEmpty() && !err.isEmpty()) { QString result = out; @@ -1748,12 +1742,12 @@ static QStringList splitLines(const QString &text) const QStringList QtcProcess::stdOutLines() const { - return splitLines(stdOut()); + return splitLines(cleanedStdOut()); } const QStringList QtcProcess::stdErrLines() const { - return splitLines(stdErr()); + return splitLines(cleanedStdErr()); } QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r) diff --git a/src/libs/utils/qtcprocess.h b/src/libs/utils/qtcprocess.h index 42c981a3431..8169e926b45 100644 --- a/src/libs/utils/qtcprocess.h +++ b/src/libs/utils/qtcprocess.h @@ -144,10 +144,10 @@ public: // These (or some of them) may be potentially moved outside of the class. // For some we may aggregate in another public utils class (or subclass of QtcProcess)? - // TODO: How below 3 methods relate to QtcProcess? Action: move them somewhere else. + // TODO: How below 2 methods relate to QtcProcess? + // Action: move/merge them somewhere else, FilePath::searchInPath() ? // Helpers to find binaries. Do not use it for other path variables // and file types. - static QString locateBinary(const QString &binary); static QString locateBinary(const QString &path, const QString &binary); static QString normalizeNewlines(const QString &text); @@ -189,8 +189,8 @@ public: QString stdOut() const; // possibly with CR QString stdErr() const; // possibly with CR - QString cleanedStdOut() const; // with CR removed - QString cleanedStdErr() const; // with CR removed + QString cleanedStdOut() const; // with sequences of CR squashed and CR LF replaced by LF + QString cleanedStdErr() const; // with sequences of CR squashed and CR LF replaced by LF const QStringList stdOutLines() const; // split, CR removed const QStringList stdErrLines() const; // split, CR removed diff --git a/src/libs/utils/shellcommand.cpp b/src/libs/utils/shellcommand.cpp index 6f8a49de019..81c293c8d99 100644 --- a/src/libs/utils/shellcommand.cpp +++ b/src/libs/utils/shellcommand.cpp @@ -271,8 +271,8 @@ void ShellCommand::run(QFutureInterface &future) proc.setExitCodeInterpreter(job.exitCodeInterpreter); proc.setTimeoutS(job.timeoutS); runCommand(proc, job.command, job.workingDirectory); - stdOut += proc.stdOut(); - stdErr += proc.stdErr(); + stdOut += proc.cleanedStdOut(); + stdErr += proc.cleanedStdErr(); d->m_lastExecExitCode = proc.exitCode(); d->m_lastExecSuccess = proc.result() == ProcessResult::FinishedWithSuccess; if (!d->m_lastExecSuccess) @@ -352,11 +352,11 @@ void ShellCommand::runFullySynchronous(QtcProcess &process, const FilePath &work process.runBlocking(); if (!d->m_aborted) { - const QString stdErr = process.stdErr(); + const QString stdErr = process.cleanedStdErr(); if (!stdErr.isEmpty() && !(d->m_flags & SuppressStdErr)) emit append(stdErr); - const QString stdOut = process.stdOut(); + const QString stdOut = process.cleanedStdOut(); if (!stdOut.isEmpty() && d->m_flags & ShowStdOut) { if (d->m_flags & SilentOutput) emit appendSilently(stdOut); diff --git a/src/libs/utils/stringutils.cpp b/src/libs/utils/stringutils.cpp index 75c37bd49f9..30f5c805aa8 100644 --- a/src/libs/utils/stringutils.cpp +++ b/src/libs/utils/stringutils.cpp @@ -29,6 +29,11 @@ #include "hostosinfo.h" #include "qtcassert.h" +#ifdef QT_WIDGETS_LIB +#include +#include +#endif + #include #include #include @@ -469,4 +474,16 @@ QTCREATOR_UTILS_EXPORT QString languageNameFromLanguageCode(const QString &langu return languageName; } +#ifdef QT_WIDGETS_LIB + +QTCREATOR_UTILS_EXPORT void setClipboardAndSelection(const QString &text) +{ + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(text); + if (clipboard->supportsSelection()) + clipboard->setText(text, QClipboard::Selection); +} + +#endif + } // namespace Utils diff --git a/src/libs/utils/stringutils.h b/src/libs/utils/stringutils.h index 70cf6738950..fd29223967b 100644 --- a/src/libs/utils/stringutils.h +++ b/src/libs/utils/stringutils.h @@ -122,4 +122,12 @@ QTCREATOR_UTILS_EXPORT QString wildcardToRegularExpression(const QString &origin QTCREATOR_UTILS_EXPORT QString languageNameFromLanguageCode(const QString &languageCode); + +#ifdef QT_WIDGETS_LIB + +// Feeds the global clipboard and, when present, the primary selection +QTCREATOR_UTILS_EXPORT void setClipboardAndSelection(const QString &text); + +#endif + } // namespace Utils diff --git a/src/libs/utils/temporaryfile.cpp b/src/libs/utils/temporaryfile.cpp index 2ee6a3a40a7..06a4ba00200 100644 --- a/src/libs/utils/temporaryfile.cpp +++ b/src/libs/utils/temporaryfile.cpp @@ -36,4 +36,6 @@ TemporaryFile::TemporaryFile(const QString &pattern) : QTC_CHECK(!QFileInfo(pattern).isAbsolute()); } +TemporaryFile::~TemporaryFile() = default; + } // namespace Utils diff --git a/src/libs/utils/temporaryfile.h b/src/libs/utils/temporaryfile.h index 2cb38e39289..a9b02adf429 100644 --- a/src/libs/utils/temporaryfile.h +++ b/src/libs/utils/temporaryfile.h @@ -35,6 +35,7 @@ class QTCREATOR_UTILS_EXPORT TemporaryFile : public QTemporaryFile { public: explicit TemporaryFile(const QString &pattern); + ~TemporaryFile(); }; } // namespace Utils diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs index b3e5adcf013..71fadc6bcf3 100644 --- a/src/libs/utils/utils.qbs +++ b/src/libs/utils/utils.qbs @@ -34,7 +34,7 @@ Project { } Depends { name: "Qt"; submodules: ["concurrent", "network", "qml", "widgets", "xml"] } - Depends { name: "Qt.macextras"; condition: qbs.targetOS.contains("macos") } + Depends { name: "Qt.macextras"; condition: Qt.core.versionMajor < 6 && qbs.targetOS.contains("macos") } Depends { name: "app_version_header" } files: [ diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index b53cf3b6f7a..0746a6b9be2 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -611,9 +611,11 @@ bool AndroidBuildApkStep::init() QStringList argumentsPasswordConcealed = arguments; if (m_signPackage) { - arguments << "--sign" << m_keystorePath.toString() << m_certificateAlias + arguments << "--release" + << "--sign" << m_keystorePath.toString() << m_certificateAlias << "--storepass" << m_keystorePasswd; - argumentsPasswordConcealed << "--sign" << "******" + argumentsPasswordConcealed << "--release" + << "--sign" << "******" << "--storepass" << "******"; if (!m_certificatePasswd.isEmpty()) { arguments << "--keypass" << m_certificatePasswd; @@ -1065,7 +1067,7 @@ QAbstractItemModel *AndroidBuildApkStep::keystoreCertificates() if (keytoolProc.result() > ProcessResult::FinishedWithError) QMessageBox::critical(nullptr, tr("Error"), tr("Failed to run keytool.")); else - model = new CertificatesModel(keytoolProc.stdOut(), this); + model = new CertificatesModel(keytoolProc.cleanedStdOut(), this); return model; } diff --git a/src/plugins/android/androiddebugsupport.cpp b/src/plugins/android/androiddebugsupport.cpp index c92ec6af462..2cc37d7e931 100644 --- a/src/plugins/android/androiddebugsupport.cpp +++ b/src/plugins/android/androiddebugsupport.cpp @@ -140,11 +140,16 @@ void AndroidDebugSupport::start() solibSearchPath.append(qtVersion->qtSoPaths()); solibSearchPath.append(uniquePaths(extraLibs)); + FilePath buildDir = AndroidManager::buildDirectory(target); const RunConfiguration *activeRunConfig = target->activeRunConfiguration(); - FilePath buildDir; if (activeRunConfig) - buildDir = activeRunConfig->buildTargetInfo().workingDirectory; + solibSearchPath.append(activeRunConfig->buildTargetInfo().workingDirectory.toString()); solibSearchPath.append(buildDir.toString()); + const auto androidLibsPath = AndroidManager::androidBuildDirectory(target) + .pathAppended("libs") + .pathAppended(AndroidManager::apkDevicePreferredAbi(target)) + .toString(); + solibSearchPath.append(androidLibsPath); solibSearchPath.removeDuplicates(); setSolibSearchPath(solibSearchPath); qCDebug(androidDebugSupportLog) << "SoLibSearchPath: "<value(); diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp index 3dbee9e59a1..974e6c11638 100644 --- a/src/plugins/android/androidmanager.cpp +++ b/src/plugins/android/androidmanager.cpp @@ -787,8 +787,8 @@ SdkToolResult AndroidManager::runCommand(const CommandLine &command, qCDebug(androidManagerLog) << "Running command (sync):" << command.toUserOutput(); cmdProc.setCommand(command); cmdProc.runBlocking(EventLoopMode::On); - cmdResult.m_stdOut = cmdProc.stdOut().trimmed(); - cmdResult.m_stdErr = cmdProc.stdErr().trimmed(); + cmdResult.m_stdOut = cmdProc.cleanedStdOut().trimmed(); + cmdResult.m_stdErr = cmdProc.cleanedStdErr().trimmed(); cmdResult.m_success = cmdProc.result() == ProcessResult::FinishedWithSuccess; qCDebug(androidManagerLog) << "Command finshed (sync):" << command.toUserOutput() << "Success:" << cmdResult.m_success diff --git a/src/plugins/android/androidsdkmanager.cpp b/src/plugins/android/androidsdkmanager.cpp index 628f245c349..960509e827c 100644 --- a/src/plugins/android/androidsdkmanager.cpp +++ b/src/plugins/android/androidsdkmanager.cpp @@ -186,7 +186,7 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar proc.runBlocking(EventLoopMode::On); if (assertionFound) { output.success = false; - output.stdOutput = proc.stdOut(); + output.stdOutput = proc.cleanedStdOut(); output.stdError = QCoreApplication::translate("Android::Internal::AndroidSdkManager", "The operation requires user interaction. " "Use the \"sdkmanager\" command-line tool."); diff --git a/src/plugins/autotest/boost/boosttestoutputreader.cpp b/src/plugins/autotest/boost/boosttestoutputreader.cpp index a9668fc8e80..b87f9ab764b 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.cpp +++ b/src/plugins/autotest/boost/boosttestoutputreader.cpp @@ -51,10 +51,8 @@ BoostTestOutputReader::BoostTestOutputReader(const QFutureInterfaceexitCode(); if (m_reportLevel == ReportLevel::No && m_testCaseCount != -1) { int reportedFailsAndSkips = m_summary[ResultType::Fail] + m_summary[ResultType::Skip]; diff --git a/src/plugins/autotest/boost/boosttestoutputreader.h b/src/plugins/autotest/boost/boosttestoutputreader.h index b5cab378a7c..2bfd9af3f94 100644 --- a/src/plugins/autotest/boost/boosttestoutputreader.h +++ b/src/plugins/autotest/boost/boosttestoutputreader.h @@ -47,7 +47,7 @@ protected: TestResultPtr createDefaultResult() const override; private: - void onFinished(); + void onDone(); void sendCompleteInformation(); void handleMessageMatch(const QRegularExpressionMatch &match); void reportNoOutputFinish(const QString &description, ResultType type); diff --git a/src/plugins/autotest/gtest/gtestoutputreader.cpp b/src/plugins/autotest/gtest/gtestoutputreader.cpp index 0c9f0b87334..4935b6599b3 100644 --- a/src/plugins/autotest/gtest/gtestoutputreader.cpp +++ b/src/plugins/autotest/gtest/gtestoutputreader.cpp @@ -45,9 +45,8 @@ GTestOutputReader::GTestOutputReader(const QFutureInterface &futu , m_projectFile(projectFile) { if (m_testApplication) { - connect(m_testApplication, &Utils::QtcProcess::finished, - this, [this]() { - int exitCode = m_testApplication->exitCode(); + connect(m_testApplication, &Utils::QtcProcess::done, this, [this] { + const 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); diff --git a/src/plugins/autotest/testrunner.cpp b/src/plugins/autotest/testrunner.cpp index 942730ba9d8..90c4f72a1d0 100644 --- a/src/plugins/autotest/testrunner.cpp +++ b/src/plugins/autotest/testrunner.cpp @@ -197,7 +197,7 @@ bool TestRunner::currentConfigValid() m_fakeFutureInterface->reportFinished(); onFinished(); } else { - onProcessFinished(); + onProcessDone(); } return false; } @@ -263,21 +263,20 @@ void TestRunner::scheduleNext() return; if (!m_currentConfig->project()) - onProcessFinished(); + onProcessDone(); setUpProcess(); - QTC_ASSERT(m_currentProcess, onProcessFinished(); return); + QTC_ASSERT(m_currentProcess, onProcessDone(); return); QTC_ASSERT(!m_currentOutputReader, delete m_currentOutputReader); m_currentOutputReader = m_currentConfig->outputReader(*m_fakeFutureInterface, m_currentProcess); - QTC_ASSERT(m_currentOutputReader, onProcessFinished();return); + QTC_ASSERT(m_currentOutputReader, onProcessDone();return); connect(m_currentOutputReader, &TestOutputReader::newOutputLineAvailable, TestResultsPane::instance(), &TestResultsPane::addOutputLine); setUpProcessEnv(); - connect(m_currentProcess, &Utils::QtcProcess::finished, - this, &TestRunner::onProcessFinished); + connect(m_currentProcess, &Utils::QtcProcess::done, this, &TestRunner::onProcessDone); const int timeout = AutotestPlugin::settings()->timeout; m_cancelTimer.setInterval(timeout); m_cancelTimer.start(); @@ -292,7 +291,7 @@ void TestRunner::scheduleNext() reportResult(ResultType::MessageFatal, tr("Failed to start test for project \"%1\".").arg(m_currentConfig->displayName()) + processInformation(m_currentProcess) + rcInfo(m_currentConfig)); - onProcessFinished(); + onProcessDone(); } } @@ -315,7 +314,7 @@ void TestRunner::cancelCurrent(TestRunner::CancelReason reason) } } -void TestRunner::onProcessFinished() +void TestRunner::onProcessDone() { if (m_executingTests && m_currentConfig) { QTC_CHECK(m_fakeFutureInterface); diff --git a/src/plugins/autotest/testrunner.h b/src/plugins/autotest/testrunner.h index 961312b6410..0d41f7d161c 100644 --- a/src/plugins/autotest/testrunner.h +++ b/src/plugins/autotest/testrunner.h @@ -90,7 +90,7 @@ private: void setUpProcessEnv(); void scheduleNext(); void cancelCurrent(CancelReason reason); - void onProcessFinished(); + void onProcessDone(); void resetInternalPointers(); void runTests(); diff --git a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp index ed0c419e87e..1fddaada16c 100644 --- a/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp +++ b/src/plugins/baremetal/debugservers/uvsc/uvscserverprovider.cpp @@ -91,12 +91,12 @@ UvscServerProvider::UvscServerProvider(const UvscServerProvider &other) setEngineType(UvscEngineType); } -void UvscServerProvider::setToolsIniFile(const Utils::FilePath &toolsIniFile) +void UvscServerProvider::setToolsIniFile(const FilePath &toolsIniFile) { m_toolsIniFile = toolsIniFile; } -Utils::FilePath UvscServerProvider::toolsIniFile() const +FilePath UvscServerProvider::toolsIniFile() const { return m_toolsIniFile; } @@ -251,8 +251,7 @@ bool UvscServerProvider::fromMap(const QVariantMap &data) return true; } -Utils::FilePath UvscServerProvider::projectFilePath(DebuggerRunTool *runTool, - QString &errorMessage) const +FilePath UvscServerProvider::projectFilePath(DebuggerRunTool *runTool, QString &errorMessage) const { const FilePath projectPath = buildProjectFilePath(runTool); std::ofstream ofs(projectPath.toString().toStdString(), std::ofstream::out); @@ -332,12 +331,12 @@ void UvscServerProviderConfigWidget::discard() IDebugServerProviderConfigWidget::discard(); } -void UvscServerProviderConfigWidget::setToolsIniFile(const Utils::FilePath &toolsIniFile) +void UvscServerProviderConfigWidget::setToolsIniFile(const FilePath &toolsIniFile) { m_toolsIniChooser->setFilePath(toolsIniFile); } -Utils::FilePath UvscServerProviderConfigWidget::toolsIniFile() const +FilePath UvscServerProviderConfigWidget::toolsIniFile() const { return m_toolsIniChooser->filePath(); } @@ -386,21 +385,16 @@ UvscServerProviderRunner::UvscServerProviderRunner(ProjectExplorer::RunControl * this->runControl()->setApplicationProcessHandle(pid); reportStarted(); }); - connect(&m_process, &QtcProcess::finished, this, [this] { - const QProcess::ProcessError error = m_process.error(); - const QString message = (error == QProcess::UnknownError) - ? m_process.exitMessage() - : userMessageForProcessError(error, m_process.commandLine().executable()); - appendMessage(message, Utils::NormalMessageFormat); + connect(&m_process, &QtcProcess::done, this, [this] { + appendMessage(m_process.exitMessage(), NormalMessageFormat); reportStopped(); }); } void UvscServerProviderRunner::start() { - const QString msg = RunControl::tr("Starting %1 ...") - .arg(m_process.commandLine().toUserOutput()); - appendMessage(msg, Utils::NormalMessageFormat); + const QString msg = RunControl::tr("Starting %1 ...").arg(m_process.commandLine().displayName()); + appendMessage(msg, NormalMessageFormat); m_process.start(); } diff --git a/src/plugins/bazaar/bazaarclient.cpp b/src/plugins/bazaar/bazaarclient.cpp index 3265905531f..ccd91a236f2 100644 --- a/src/plugins/bazaar/bazaarclient.cpp +++ b/src/plugins/bazaar/bazaarclient.cpp @@ -153,7 +153,7 @@ bool BazaarClient::synchronousUncommit(const FilePath &workingDir, QtcProcess proc; vcsFullySynchronousExec(proc, workingDir, args); - VcsOutputWindow::append(proc.stdOut()); + VcsOutputWindow::append(proc.cleanedStdOut()); return proc.result() == ProcessResult::FinishedWithSuccess; } diff --git a/src/plugins/beautifier/abstractsettings.cpp b/src/plugins/beautifier/abstractsettings.cpp index d691984d62f..e9768041452 100644 --- a/src/plugins/beautifier/abstractsettings.cpp +++ b/src/plugins/beautifier/abstractsettings.cpp @@ -34,11 +34,16 @@ #include #include #include +#include #include #include +#include +#include #include +using namespace Utils; + namespace Beautifier { namespace Internal { @@ -47,12 +52,65 @@ const char COMMAND[] = "command"; const char SUPPORTED_MIME[] = "supportedMime"; } +class VersionUpdater +{ +public: + VersionUpdater() + { + QObject::connect(&m_process, &QtcProcess::done, [this] { + if (m_process.result() != ProcessResult::FinishedWithSuccess) + return; + + m_versionNumber = parseVersion(m_process.cleanedStdOut()); + if (m_versionNumber.isNull()) + m_versionNumber = parseVersion(m_process.cleanedStdErr()); + }); + } + + void setVersionRegExp(const QRegularExpression &versionRegExp) + { + m_versionRegExp = versionRegExp; + } + + void update(const FilePath &executable) + { + m_versionNumber = {}; + if (m_versionRegExp.pattern().isEmpty()) + return; + m_process.close(); + m_process.setCommand({executable, {"--version"}}); + m_process.start(); + } + + QVersionNumber version() const + { + if (m_process.state() != QProcess::NotRunning) + m_process.waitForFinished(-1); + return m_versionNumber; + } + +private: + QVersionNumber parseVersion(const QString &text) const + { + const QRegularExpressionMatch match = m_versionRegExp.match(text); + if (!match.hasMatch()) + return {}; + + return {match.captured(1).toInt(), match.captured(2).toInt()}; + } + + QRegularExpression m_versionRegExp; + mutable QtcProcess m_process; + QVersionNumber m_versionNumber; +}; + AbstractSettings::AbstractSettings(const QString &name, const QString &ending) : m_ending(ending) , m_styleDir(Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME) .pathAppended(name) .toString()) , m_name(name) + , m_versionUpdater(new VersionUpdater) { } @@ -122,29 +180,28 @@ QString AbstractSettings::styleFileName(const QString &key) const return m_styleDir.absoluteFilePath(key + m_ending); } -Utils::FilePath AbstractSettings::command() const +FilePath AbstractSettings::command() const { - return Utils::FilePath::fromString(m_command); + return FilePath::fromString(m_command); } -void AbstractSettings::setCommand(const QString &command) +void AbstractSettings::setCommand(const QString &cmd) { - if (command == m_command) + if (cmd == m_command) return; - m_command = command; - updateVersion(); + m_command = cmd; + m_versionUpdater->update(command()); } -int AbstractSettings::version() const +QVersionNumber AbstractSettings::version() const { - return m_version; + return m_versionUpdater->version(); } -void AbstractSettings::updateVersion() +void AbstractSettings::setVersionRegExp(const QRegularExpression &versionRegExp) { - // If a beautifier needs to know the current tool's version, reimplement and store the version - // in m_version. + m_versionUpdater->setVersionRegExp(versionRegExp); } QString AbstractSettings::supportedMimeTypesAsString() const @@ -157,7 +214,7 @@ void AbstractSettings::setSupportedMimeTypes(const QString &mimes) const QStringList stringTypes = mimes.split(';'); QStringList types; for (const QString &type : stringTypes) { - const Utils::MimeType mime = Utils::mimeTypeForName(type.trimmed()); + const MimeType mime = mimeTypeForName(type.trimmed()); if (!mime.isValid()) continue; const QString canonicalName = mime.name(); @@ -179,8 +236,8 @@ bool AbstractSettings::isApplicable(const Core::IDocument *document) const if (m_supportedMimeTypes.isEmpty()) return true; - const Utils::MimeType documentMimeType = Utils::mimeTypeForName(document->mimeType()); - return Utils::anyOf(m_supportedMimeTypes, [&documentMimeType](const QString &mime) { + const MimeType documentMimeType = mimeTypeForName(document->mimeType()); + return anyOf(m_supportedMimeTypes, [&documentMimeType](const QString &mime) { return documentMimeType.inherits(mime); }); } @@ -246,7 +303,7 @@ void AbstractSettings::save() continue; } - Utils::FileSaver saver(Utils::FilePath::fromUserInput(fi.absoluteFilePath())); + FileSaver saver(FilePath::fromUserInput(fi.absoluteFilePath())); if (saver.hasError()) { BeautifierPlugin::showError(tr("Cannot open file \"%1\": %2.") .arg(saver.filePath().toUserOutput()) diff --git a/src/plugins/beautifier/abstractsettings.h b/src/plugins/beautifier/abstractsettings.h index ae61bde2676..ae39c6ce690 100644 --- a/src/plugins/beautifier/abstractsettings.h +++ b/src/plugins/beautifier/abstractsettings.h @@ -35,12 +35,21 @@ #include #include +#include + +QT_BEGIN_NAMESPACE +class QRegularExpression; +class QVersionNumber; +QT_END_NAMESPACE + namespace Core { class IDocument; } namespace Utils { class FilePath; } namespace Beautifier { namespace Internal { +class VersionUpdater; + class AbstractSettings : public QObject { Q_OBJECT @@ -66,9 +75,8 @@ public: virtual QString styleFileName(const QString &key) const; Utils::FilePath command() const; - void setCommand(const QString &command); - int version() const; - virtual void updateVersion(); + void setCommand(const QString &cmd); + QVersionNumber version() const; QString supportedMimeTypesAsString() const; void setSupportedMimeTypes(const QString &mimes); @@ -81,9 +89,10 @@ signals: void supportedMimeTypesChanged(); protected: + void setVersionRegExp(const QRegularExpression &versionRegExp); + QMap m_styles; QMap m_settings; - int m_version = 0; QString m_ending; QDir m_styleDir; @@ -92,6 +101,7 @@ protected: private: QString m_name; + std::unique_ptr m_versionUpdater; QStringList m_stylesToRemove; QSet m_changedStyles; QString m_command; diff --git a/src/plugins/beautifier/artisticstyle/artisticstyle.cpp b/src/plugins/beautifier/artisticstyle/artisticstyle.cpp index a8851b43cc5..04fda15a819 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstyle.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstyle.cpp @@ -53,6 +53,7 @@ #include #include +#include using namespace TextEditor; @@ -150,10 +151,10 @@ Command ArtisticStyle::command(const QString &cfgFile) const command.addOption("-q"); command.addOption("--options=" + cfgFile); - const int version = m_settings.version(); - if (version > ArtisticStyleSettings::Version_2_03) { + const QVersionNumber version = m_settings.version(); + if (version > QVersionNumber(2, 3)) { command.setProcessing(Command::PipeProcessing); - if (version == ArtisticStyleSettings::Version_2_04) + if (version == QVersionNumber(2, 4)) command.setPipeAddsNewline(true); command.setReturnsCRLF(Utils::HostOsInfo::isWindowsHost()); command.addOption("-z2"); diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp index ed6d0b91590..5e7f8425cb9 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp @@ -57,9 +57,7 @@ const char SETTINGS_NAME[] = "artisticstyle"; ArtisticStyleSettings::ArtisticStyleSettings() : AbstractSettings(SETTINGS_NAME, ".astyle") { - connect(&m_versionWatcher, &QFutureWatcherBase::finished, - this, &ArtisticStyleSettings::helperSetVersion); - + setVersionRegExp(QRegularExpression("([2-9]{1})\\.([0-9]{1,2})(\\.[1-9]{1})?$")); setCommand("astyle"); m_settings.insert(USE_OTHER_FILES, QVariant(true)); m_settings.insert(USE_SPECIFIC_CONFIG_FILE, QVariant(false)); @@ -70,48 +68,6 @@ ArtisticStyleSettings::ArtisticStyleSettings() : read(); } -static int parseVersion(const QString &text) -{ - // The version in Artistic Style is printed like "Artistic Style Version 2.04" - const QRegularExpression rx("([2-9]{1})\\.([0-9]{1,2})(\\.[1-9]{1})?$"); - const QRegularExpressionMatch match = rx.match(text); - if (match.hasMatch()) { - const int major = match.captured(1).toInt() * 100; - const int minor = match.captured(2).toInt(); - return major + minor; - } - return 0; -} - -static int updateVersionHelper(const FilePath &command) -{ - QtcProcess process; - process.setCommand({command, {"--version"}}); - process.runBlocking(); - if (process.result() != ProcessResult::FinishedWithSuccess) - return 0; - - // Astyle prints the version on stdout or stderr, depending on platform - const int version = parseVersion(process.stdOut().trimmed()); - if (version != 0) - return version; - return parseVersion(process.stdErr().trimmed()); -} - -void ArtisticStyleSettings::updateVersion() -{ - if (m_versionFuture.isRunning()) - m_versionFuture.cancel(); - - m_versionFuture = runAsync(updateVersionHelper, command()); - m_versionWatcher.setFuture(m_versionFuture); -} - -void ArtisticStyleSettings::helperSetVersion() -{ - m_version = m_versionWatcher.result(); -} - bool ArtisticStyleSettings::useOtherFiles() const { return m_settings.value(USE_OTHER_FILES).toBool(); @@ -132,12 +88,12 @@ void ArtisticStyleSettings::setUseSpecificConfigFile(bool useSpecificConfigFile) m_settings.insert(USE_SPECIFIC_CONFIG_FILE, QVariant(useSpecificConfigFile)); } -Utils::FilePath ArtisticStyleSettings::specificConfigFile() const +FilePath ArtisticStyleSettings::specificConfigFile() const { - return Utils::FilePath::fromString(m_settings.value(SPECIFIC_CONFIG_FILE).toString()); + return FilePath::fromString(m_settings.value(SPECIFIC_CONFIG_FILE).toString()); } -void ArtisticStyleSettings::setSpecificConfigFile(const Utils::FilePath &specificConfigFile) +void ArtisticStyleSettings::setSpecificConfigFile(const FilePath &specificConfigFile) { m_settings.insert(SPECIFIC_CONFIG_FILE, QVariant(specificConfigFile.toString())); } @@ -182,7 +138,7 @@ QString ArtisticStyleSettings::documentationFilePath() const void ArtisticStyleSettings::createDocumentationFile() const { - Utils::QtcProcess process; + QtcProcess process; process.setTimeoutS(2); process.setCommand({command(), {"-h"}}); process.runBlocking(); @@ -204,7 +160,7 @@ void ArtisticStyleSettings::createDocumentationFile() const stream.writeStartElement(Constants::DOCUMENTATION_XMLROOT); // astyle writes its output to 'error'... - const QStringList lines = process.stdErr().split(QLatin1Char('\n')); + const QStringList lines = process.cleanedStdErr().split(QLatin1Char('\n')); QStringList keys; QStringList docu; for (QString line : lines) { diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.h b/src/plugins/beautifier/artisticstyle/artisticstylesettings.h index e0fa1b8866e..cf125810317 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.h +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.h @@ -29,9 +29,6 @@ #include -#include -#include - namespace Beautifier { namespace Internal { @@ -40,15 +37,8 @@ class ArtisticStyleSettings : public AbstractSettings Q_OBJECT public: - enum ArtisticStyleVersion { - Version_2_03 = 203, - Version_2_04 = 204 - }; - ArtisticStyleSettings(); - void updateVersion() override; - bool useOtherFiles() const; void setUseOtherFiles(bool useOtherFiles); @@ -69,11 +59,6 @@ public: QString documentationFilePath() const override; void createDocumentationFile() const override; - -private: - void helperSetVersion(); - QFuture m_versionFuture; - QFutureWatcher m_versionWatcher; }; } // namespace Internal diff --git a/src/plugins/beautifier/uncrustify/uncrustify.cpp b/src/plugins/beautifier/uncrustify/uncrustify.cpp index 689ef3714a0..370a7f37a00 100644 --- a/src/plugins/beautifier/uncrustify/uncrustify.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustify.cpp @@ -49,6 +49,7 @@ #include #include +#include using namespace TextEditor; @@ -180,7 +181,7 @@ Command Uncrustify::command(const QString &cfgFile, bool fragment) const Command command; command.setExecutable(m_settings.command().toString()); command.setProcessing(Command::PipeProcessing); - if (m_settings.version() >= 62) { + if (m_settings.version() >= QVersionNumber(0, 62)) { command.addOption("--assume"); command.addOption("%file"); } else { diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp index 77b775bc9c3..fbc8bfe079b 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.cpp @@ -30,7 +30,6 @@ #include "../beautifierconstants.h" #include - #include #include @@ -56,6 +55,7 @@ const char SETTINGS_NAME[] = "uncrustify"; UncrustifySettings::UncrustifySettings() : AbstractSettings(SETTINGS_NAME, ".cfg") { + setVersionRegExp(QRegularExpression("([0-9]{1})\\.([0-9]{2})")); setCommand("uncrustify"); m_settings.insert(USE_OTHER_FILES, QVariant(true)); m_settings.insert(USE_HOME_FILE, QVariant(false)); @@ -210,33 +210,5 @@ void UncrustifySettings::createDocumentationFile() const } } -static bool parseVersion(const QString &text, int &version) -{ - // The version in Uncrustify is printed like "uncrustify 0.62" - const QRegularExpression rx("([0-9]{1})\\.([0-9]{2})"); - const QRegularExpressionMatch match = rx.match(text); - if (!match.hasMatch()) - return false; - - const int major = match.captured(1).toInt() * 100; - const int minor = match.captured(2).toInt(); - version = major + minor; - return true; -} - -void UncrustifySettings::updateVersion() -{ - m_versionProcess.reset(new QtcProcess); - connect(m_versionProcess.get(), &QtcProcess::finished, this, [this] { - if (m_versionProcess->exitStatus() == QProcess::NormalExit) { - if (!parseVersion(QString::fromUtf8(m_versionProcess->readAllStandardOutput()), m_version)) - parseVersion(QString::fromUtf8(m_versionProcess->readAllStandardError()), m_version); - } - m_versionProcess.release()->deleteLater(); - }); - m_versionProcess->setCommand({ command(), { "--version" } }); - m_versionProcess->start(); -} - } // namespace Internal } // namespace Beautifier diff --git a/src/plugins/beautifier/uncrustify/uncrustifysettings.h b/src/plugins/beautifier/uncrustify/uncrustifysettings.h index 8c2db0ef2c4..e2cd9e99ec2 100644 --- a/src/plugins/beautifier/uncrustify/uncrustifysettings.h +++ b/src/plugins/beautifier/uncrustify/uncrustifysettings.h @@ -26,9 +26,6 @@ #pragma once #include "../abstractsettings.h" -#include - -namespace Utils { class QtcProcess; } namespace Beautifier { namespace Internal { @@ -59,16 +56,11 @@ public: QString documentationFilePath() const override; void createDocumentationFile() const override; - void updateVersion() override; - Utils::FilePath specificConfigFile() const; void setSpecificConfigFile(const Utils::FilePath &filePath); bool useSpecificConfigFile() const; void setUseSpecificConfigFile(bool useConfigFile); - -private: - std::unique_ptr m_versionProcess; }; } // namespace Internal diff --git a/src/plugins/boot2qt/qdbdevice.cpp b/src/plugins/boot2qt/qdbdevice.cpp index f6c3f6312d7..8017a39a1e6 100644 --- a/src/plugins/boot2qt/qdbdevice.cpp +++ b/src/plugins/boot2qt/qdbdevice.cpp @@ -88,8 +88,8 @@ public: private: void handleDone() { - const QString stdOut = m_appRunner.stdOut(); - const QString stdErr = m_appRunner.stdErr(); + const QString stdOut = m_appRunner.cleanedStdOut(); + const QString stdErr = m_appRunner.cleanedStdErr(); // FIXME: Needed in a post-adb world? // adb does not forward exit codes and all stderr goes to stdout. diff --git a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp index 44e70d01922..e09b134e74f 100644 --- a/src/plugins/boot2qt/qdbdevicedebugsupport.cpp +++ b/src/plugins/boot2qt/qdbdevicedebugsupport.cpp @@ -55,7 +55,7 @@ public: setId("QdbDebuggeeRunner"); connect(&m_launcher, &QtcProcess::started, this, &RunWorker::reportStarted); - connect(&m_launcher, &QtcProcess::finished, this, &RunWorker::reportStopped); + connect(&m_launcher, &QtcProcess::done, this, &RunWorker::reportStopped); connect(&m_launcher, &QtcProcess::readyReadStandardOutput, [this] { appendMessage(QString::fromUtf8(m_launcher.readAllStandardOutput()), StdOutFormat); diff --git a/src/plugins/clangcodemodel/CMakeLists.txt b/src/plugins/clangcodemodel/CMakeLists.txt index 896df4e18ce..e64d17b5f01 100644 --- a/src/plugins/clangcodemodel/CMakeLists.txt +++ b/src/plugins/clangcodemodel/CMakeLists.txt @@ -22,6 +22,7 @@ add_qtc_plugin(ClangCodeModel clangdquickfixfactory.cpp clangdquickfixfactory.h clangdqpropertyhighlighter.cpp clangdqpropertyhighlighter.h clangdsemantichighlighting.cpp clangdsemantichighlighting.h + clangdswitchdecldef.cpp clangdswitchdecldef.h clangeditordocumentprocessor.cpp clangeditordocumentprocessor.h clangfixitoperation.cpp clangfixitoperation.h clangdlocatorfilters.cpp clangdlocatorfilters.h diff --git a/src/plugins/clangcodemodel/clangcodemodel.qbs b/src/plugins/clangcodemodel/clangcodemodel.qbs index 19a0e7604a9..bd0f341cc50 100644 --- a/src/plugins/clangcodemodel/clangcodemodel.qbs +++ b/src/plugins/clangcodemodel/clangcodemodel.qbs @@ -46,6 +46,8 @@ QtcPlugin { "clangdquickfixfactory.h", "clangdsemantichighlighting.cpp", "clangdsemantichighlighting.h", + "clangdswitchdecldef.cpp", + "clangdswitchdecldef.h", "clangeditordocumentprocessor.cpp", "clangeditordocumentprocessor.h", "clangfixitoperation.cpp", diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 326539e5619..96034c1052c 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -30,6 +30,7 @@ #include "clangdast.h" #include "clangdfollowsymbol.h" #include "clangdlocatorfilters.h" +#include "clangdswitchdecldef.h" #include "clangpreprocessorassistproposalitem.h" #include "clangtextmark.h" #include "clangutils.h" @@ -59,7 +60,6 @@ #include #include #include -#include #include #include #include @@ -117,8 +117,8 @@ namespace ClangCodeModel { namespace Internal { Q_LOGGING_CATEGORY(clangdLog, "qtc.clangcodemodel.clangd", QtWarningMsg); +Q_LOGGING_CATEGORY(clangdLogAst, "qtc.clangcodemodel.clangd.ast", QtWarningMsg); static Q_LOGGING_CATEGORY(clangdLogServer, "qtc.clangcodemodel.clangd.server", QtWarningMsg); -static Q_LOGGING_CATEGORY(clangdLogAst, "qtc.clangcodemodel.clangd.ast", QtWarningMsg); static Q_LOGGING_CATEGORY(clangdLogCompletion, "qtc.clangcodemodel.clangd.completion", QtWarningMsg); static QString indexingToken() { return "backgroundIndexProgress"; } @@ -310,58 +310,6 @@ public: bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences(); }; -class SwitchDeclDefData { -public: - SwitchDeclDefData(quint64 id, TextDocument *doc, const QTextCursor &cursor, - CppEditor::CppEditorWidget *editorWidget, - const Utils::LinkHandler &callback) - : id(id), document(doc), uri(DocumentUri::fromFilePath(doc->filePath())), - cursor(cursor), editorWidget(editorWidget), callback(callback) {} - - Utils::optional getFunctionNode() const - { - QTC_ASSERT(ast, return {}); - - const ClangdAstPath path = getAstPath(*ast, Range(cursor)); - for (auto it = path.rbegin(); it != path.rend(); ++it) { - if (it->role() == "declaration" - && (it->kind() == "CXXMethod" || it->kind() == "CXXConversion" - || it->kind() == "CXXConstructor" || it->kind() == "CXXDestructor")) { - return *it; - } - } - return {}; - } - - QTextCursor cursorForFunctionName(const ClangdAstNode &functionNode) const - { - QTC_ASSERT(docSymbols, return {}); - - const auto symbolList = Utils::get_if>(&*docSymbols); - if (!symbolList) - return {}; - const Range &astRange = functionNode.range(); - QList symbolsToCheck = *symbolList; - while (!symbolsToCheck.isEmpty()) { - const DocumentSymbol symbol = symbolsToCheck.takeFirst(); - if (symbol.range() == astRange) - return symbol.selectionRange().start().toTextCursor(document->document()); - if (symbol.range().contains(astRange)) - symbolsToCheck << symbol.children().value_or(QList()); - } - return {}; - } - - const quint64 id; - const QPointer document; - const DocumentUri uri; - const QTextCursor cursor; - const QPointer editorWidget; - Utils::LinkHandler callback; - Utils::optional docSymbols; - Utils::optional ast; -}; - class LocalRefsData { public: LocalRefsData(quint64 id, TextDocument *doc, const QTextCursor &cursor, @@ -699,7 +647,7 @@ public: const CppEditor::ClangdSettings::Data settings; QHash runningFindUsages; ClangdFollowSymbol *followSymbol = nullptr; - Utils::optional switchDeclDefData; + ClangdSwitchDeclDef *switchDeclDef = nullptr; Utils::optional localRefsData; Utils::optional versionNumber; @@ -741,6 +689,7 @@ public: private: QIcon icon() const override; + QString text() const override; }; class ClangdClient::ClangdCompletionAssistProcessor : public LanguageClientCompletionAssistProcessor @@ -1015,15 +964,6 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir) QTC_CHECK(d->runningFindUsages.isEmpty()); }); - connect(documentSymbolCache(), &DocumentSymbolCache::gotSymbols, this, - [this](const DocumentUri &uri, const DocumentSymbolsResult &symbols) { - if (!d->switchDeclDefData || d->switchDeclDefData->uri != uri) - return; - d->switchDeclDefData->docSymbols = symbols; - if (d->switchDeclDefData->ast) - d->handleDeclDefSwitchReplies(); - }); - start(); } @@ -1682,26 +1622,13 @@ void ClangdClient::switchDeclDef(TextDocument *document, const QTextCursor &curs qCDebug(clangdLog) << "switch decl/dev requested" << document->filePath() << cursor.blockNumber() << cursor.positionInBlock(); - d->switchDeclDefData.emplace(++d->nextJobId, document, cursor, editorWidget, callback); - - // Retrieve AST and document symbols. - const auto astHandler = [this, id = d->switchDeclDefData->id](const ClangdAstNode &ast, - const MessageId &) { - qCDebug(clangdLog) << "received ast for decl/def switch"; - if (!d->switchDeclDefData || d->switchDeclDefData->id != id - || !d->switchDeclDefData->document) - return; - if (!ast.isValid()) { - d->switchDeclDefData.reset(); - return; - } - d->switchDeclDefData->ast = ast; - if (d->switchDeclDefData->docSymbols) - d->handleDeclDefSwitchReplies(); - - }; - d->getAndHandleAst(document, astHandler, AstCallbackMode::SyncIfPossible); - documentSymbolCache()->requestSymbols(d->switchDeclDefData->uri, Schedule::Now); + if (d->switchDeclDef) + delete d->switchDeclDef; + d->switchDeclDef = new ClangdSwitchDeclDef(this, document, cursor, editorWidget, callback); + connect(d->switchDeclDef, &ClangdSwitchDeclDef::done, this, [this] { + delete d->switchDeclDef; + d->switchDeclDef = nullptr; + }); } void ClangdClient::switchHeaderSource(const Utils::FilePath &filePath, bool inNextSplit) @@ -1979,35 +1906,6 @@ void ClangdClient::setVirtualRanges(const Utils::FilePath &filePath, const QList d->highlightingData[doc].virtualRanges = {ranges, revision}; } -void ClangdClient::Private::handleDeclDefSwitchReplies() -{ - if (!switchDeclDefData->document) { - switchDeclDefData.reset(); - return; - } - - // Find the function declaration or definition associated with the cursor. - // For instance, the cursor could be somwehere inside a function body or - // on a function return type, or ... - if (clangdLogAst().isDebugEnabled()) - switchDeclDefData->ast->print(0); - const Utils::optional functionNode = switchDeclDefData->getFunctionNode(); - if (!functionNode) { - switchDeclDefData.reset(); - return; - } - - // Unfortunately, the AST does not contain the location of the actual function name symbol, - // so we have to look for it in the document symbols. - const QTextCursor funcNameCursor = switchDeclDefData->cursorForFunctionName(*functionNode); - if (!funcNameCursor.isNull()) { - q->followSymbol(switchDeclDefData->document.data(), funcNameCursor, - switchDeclDefData->editorWidget, std::move(switchDeclDefData->callback), - true, false); - } - switchDeclDefData.reset(); -} - Utils::optional ClangdClient::Private::getContainingFunctionName( const ClangdAstPath &astPath, const Range& range) { @@ -2551,6 +2449,8 @@ ClangdCompletionItem::SpecialQtType ClangdCompletionItem::getQtType(const Comple QIcon ClangdCompletionItem::icon() const { + if (isDeprecated()) + return Utils::Icons::WARNING.icon(); const SpecialQtType qtType = getQtType(item()); switch (qtType) { case SpecialQtType::Signal: @@ -2566,6 +2466,14 @@ QIcon ClangdCompletionItem::icon() const return LanguageClientCompletionItem::icon(); } +QString ClangdCompletionItem::text() const +{ + const QString clangdValue = LanguageClientCompletionItem::text(); + if (isDeprecated()) + return "[[deprecated]]" + clangdValue; + return clangdValue; +} + MessageId ClangdClient::Private::getAndHandleAst(const TextDocOrFile &doc, const AstHandler &astHandler, AstCallbackMode callbackMode, const Range &range) diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index 13530b168f7..2aec6f8b570 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -51,6 +51,7 @@ namespace Internal { class ClangdAstNode; Q_DECLARE_LOGGING_CATEGORY(clangdLog); +Q_DECLARE_LOGGING_CATEGORY(clangdLogAst); void setupClangdConfigFile(); diff --git a/src/plugins/clangcodemodel/clangdfollowsymbol.cpp b/src/plugins/clangcodemodel/clangdfollowsymbol.cpp index 53ec97342f4..4c7400914ab 100644 --- a/src/plugins/clangcodemodel/clangdfollowsymbol.cpp +++ b/src/plugins/clangcodemodel/clangdfollowsymbol.cpp @@ -38,6 +38,7 @@ #include #include +#include #include using namespace CppEditor; @@ -133,6 +134,7 @@ public: SymbolDataList symbolsToDisplay; std::set openedFiles; VirtualFunctionAssistProcessor *virtualFuncAssistProcessor = nullptr; + QMetaObject::Connection focusChangedConnection; bool finished = false; }; @@ -143,6 +145,16 @@ ClangdFollowSymbol::ClangdFollowSymbol(ClangdClient *client, const QTextCursor & d(new Private(this, client, cursor, editorWidget, document->filePath(), callback, openInSplit)) { + // Abort if the user does something else with the document in the meantime. + connect(document, &TextDocument::contentsChanged, this, &ClangdFollowSymbol::done, + Qt::QueuedConnection); + if (editorWidget) { + connect(editorWidget, &CppEditorWidget::cursorPositionChanged, + this, &ClangdFollowSymbol::done, Qt::QueuedConnection); + } + d->focusChangedConnection = connect(qApp, &QApplication::focusChanged, + this, &ClangdFollowSymbol::done, Qt::QueuedConnection); + // Step 1: Follow the symbol via "Go to Definition". At the same time, request the // AST node corresponding to the cursor position, so we can find out whether // we have to look for overrides. @@ -402,8 +414,10 @@ void ClangdFollowSymbol::Private::handleGotoImplementationResult( // As soon as we know that there is more than one candidate, we start the code assist // procedure, to let the user know that things are happening. - if (allLinks.size() > 1 && !virtualFuncAssistProcessor && editorWidget) + if (allLinks.size() > 1 && !virtualFuncAssistProcessor && editorWidget) { + QObject::disconnect(focusChangedConnection); editorWidget->invokeTextEditorWidgetAssist(FollowSymbol, &virtualFuncAssistProvider); + } if (!pendingGotoImplRequests.isEmpty()) return; diff --git a/src/plugins/clangcodemodel/clangdswitchdecldef.cpp b/src/plugins/clangcodemodel/clangdswitchdecldef.cpp new file mode 100644 index 00000000000..d3ce7187631 --- /dev/null +++ b/src/plugins/clangcodemodel/clangdswitchdecldef.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2022 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 "clangdswitchdecldef.h" + +#include "clangdast.h" +#include "clangdclient.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace CppEditor; +using namespace LanguageClient; +using namespace LanguageServerProtocol; +using namespace TextEditor; +using namespace Utils; + +namespace ClangCodeModel::Internal { + +class ClangdSwitchDeclDef::Private +{ +public: + Private(ClangdSwitchDeclDef * q, ClangdClient *client, TextDocument *doc, + const QTextCursor &cursor, CppEditorWidget *editorWidget, const LinkHandler &callback) + : q(q), client(client), document(doc), uri(DocumentUri::fromFilePath(doc->filePath())), + cursor(cursor), editorWidget(editorWidget), callback(callback) + {} + + optional getFunctionNode() const; + QTextCursor cursorForFunctionName(const ClangdAstNode &functionNode) const; + void handleDeclDefSwitchReplies(); + + ClangdSwitchDeclDef * const q; + ClangdClient * const client; + const QPointer document; + const DocumentUri uri; + const QTextCursor cursor; + const QPointer editorWidget; + const LinkHandler callback; + optional ast; + optional docSymbols; +}; + +ClangdSwitchDeclDef::ClangdSwitchDeclDef(ClangdClient *client, TextDocument *doc, + const QTextCursor &cursor, CppEditorWidget *editorWidget, const LinkHandler &callback) + : QObject(client), d(new Private(this, client, doc, cursor, editorWidget, callback)) +{ + // Abort if the user does something else with the document in the meantime. + connect(doc, &TextDocument::contentsChanged, this, &ClangdSwitchDeclDef::done, + Qt::QueuedConnection); + if (editorWidget) { + connect(editorWidget, &CppEditorWidget::cursorPositionChanged, + this, &ClangdSwitchDeclDef::done, Qt::QueuedConnection); + } + connect(qApp, &QApplication::focusChanged, + this, &ClangdSwitchDeclDef::done, Qt::QueuedConnection); + + connect(client->documentSymbolCache(), &DocumentSymbolCache::gotSymbols, this, + [this](const DocumentUri &uri, const DocumentSymbolsResult &symbols) { + if (uri != d->uri) + return; + d->docSymbols = symbols; + if (d->ast) + d->handleDeclDefSwitchReplies(); + }); + + + // Retrieve AST and document symbols. + const auto astHandler = [this, self = QPointer(this)] + (const ClangdAstNode &ast, const MessageId &) { + qCDebug(clangdLog) << "received ast for decl/def switch"; + if (!self) + return; + if (!d->document) { + emit done(); + return; + } + if (!ast.isValid()) { + emit done(); + return; + } + d->ast = ast; + if (d->docSymbols) + d->handleDeclDefSwitchReplies(); + + }; + client->getAndHandleAst(doc, astHandler, ClangdClient::AstCallbackMode::SyncIfPossible, {}); + client->documentSymbolCache()->requestSymbols(d->uri, Schedule::Now); +} + +ClangdSwitchDeclDef::~ClangdSwitchDeclDef() +{ + delete d; +} + +optional ClangdSwitchDeclDef::Private::getFunctionNode() const +{ + QTC_ASSERT(ast, return {}); + + const ClangdAstPath path = getAstPath(*ast, Range(cursor)); + for (auto it = path.rbegin(); it != path.rend(); ++it) { + if (it->role() == "declaration" + && (it->kind() == "CXXMethod" || it->kind() == "CXXConversion" + || it->kind() == "CXXConstructor" || it->kind() == "CXXDestructor" + || it->kind() == "Function")) { + return *it; + } + } + return {}; +} + +QTextCursor ClangdSwitchDeclDef::Private::cursorForFunctionName(const ClangdAstNode &functionNode) const +{ + QTC_ASSERT(docSymbols, return {}); + + const auto symbolList = Utils::get_if>(&*docSymbols); + if (!symbolList) + return {}; + const Range &astRange = functionNode.range(); + QList symbolsToCheck = *symbolList; + while (!symbolsToCheck.isEmpty()) { + const DocumentSymbol symbol = symbolsToCheck.takeFirst(); + if (symbol.range() == astRange) + return symbol.selectionRange().start().toTextCursor(document->document()); + if (symbol.range().contains(astRange)) + symbolsToCheck << symbol.children().value_or(QList()); + } + return {}; +} + +void ClangdSwitchDeclDef::Private::handleDeclDefSwitchReplies() +{ + if (!document) { + emit q->done(); + return; + } + + // Find the function declaration or definition associated with the cursor. + // For instance, the cursor could be somwehere inside a function body or + // on a function return type, or ... + if (clangdLogAst().isDebugEnabled()) + ast->print(0); + const Utils::optional functionNode = getFunctionNode(); + if (!functionNode) { + emit q->done(); + return; + } + + // Unfortunately, the AST does not contain the location of the actual function name symbol, + // so we have to look for it in the document symbols. + const QTextCursor funcNameCursor = cursorForFunctionName(*functionNode); + if (!funcNameCursor.isNull()) { + client->followSymbol(document.data(), funcNameCursor, editorWidget, callback, + true, false); + } + emit q->done(); +} + +} // namespace ClangCodeModel::Internal diff --git a/src/plugins/clangcodemodel/clangdswitchdecldef.h b/src/plugins/clangcodemodel/clangdswitchdecldef.h new file mode 100644 index 00000000000..8c278bf6555 --- /dev/null +++ b/src/plugins/clangcodemodel/clangdswitchdecldef.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include + +#include + +namespace CppEditor { class CppEditorWidget; } +namespace TextEditor { class TextDocument; } + +QT_BEGIN_NAMESPACE +class QTextCursor; +QT_END_NAMESPACE + +namespace ClangCodeModel::Internal { +class ClangdClient; + +class ClangdSwitchDeclDef : public QObject +{ + Q_OBJECT +public: + ClangdSwitchDeclDef(ClangdClient *client, TextEditor::TextDocument *doc, + const QTextCursor &cursor, CppEditor::CppEditorWidget *editorWidget, + const Utils::LinkHandler &callback); + ~ClangdSwitchDeclDef(); + +signals: + void done(); + +private: + class Private; + Private * const d; +}; + +} // namespace ClangCodeModel::Internal diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index a33d2863563..1437aff83f6 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -62,10 +62,12 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -124,6 +126,40 @@ static Client *clientForGeneratedFile(const Utils::FilePath &filePath) return nullptr; } +static void checkSystemForClangdSuitability() +{ + if (ClangdSettings::haveCheckedHardwareRequirements()) + return; + if (ClangdSettings::hardwareFulfillsRequirements()) + return; + + ClangdSettings::setUseClangd(false); + const QString warnStr = ClangModelManagerSupport::tr("The use of clangd for the C/C++ " + "code model was disabled, because it is likely that its memory requirements " + "would be higher than what your system can handle."); + const Utils::Id clangdWarningSetting("WarnAboutClangd"); + Utils::InfoBarEntry info(clangdWarningSetting, warnStr); + info.setDetailsWidgetCreator([] { + const auto label = new QLabel(ClangModelManagerSupport::tr( + "With clangd enabled, Qt Creator fully supports modern C++ " + "when highlighting code, completing symbols and so on.
" + "This comes at a higher cost in terms of CPU load and memory usage compared " + "to the built-in code model, which therefore might be the better choice " + "on older machines and/or with legacy code.
" + "You can enable/disable and fine-tune clangd here.")); + label->setWordWrap(true); + QObject::connect(label, &QLabel::linkActivated, [] { + Core::ICore::showOptionsDialog(CppEditor::Constants::CPP_CLANGD_SETTINGS_ID); + }); + return label; + }); + info.addCustomButton(ClangModelManagerSupport::tr("Enable Anyway"), [clangdWarningSetting] { + ClangdSettings::setUseClangd(true); + Core::ICore::infoBar()->removeInfo(clangdWarningSetting); + }); + Core::ICore::infoBar()->addInfo(info); +} + ClangModelManagerSupport::ClangModelManagerSupport() { QTC_CHECK(!m_instance); @@ -132,6 +168,7 @@ ClangModelManagerSupport::ClangModelManagerSupport() watchForExternalChanges(); watchForInternalChanges(); setupClangdConfigFile(); + checkSystemForClangdSuitability(); cppModelManager()->setCurrentDocumentFilter(std::make_unique()); cppModelManager()->setLocatorFilter(std::make_unique()); cppModelManager()->setClassesFilter(std::make_unique()); diff --git a/src/plugins/clangcodemodel/clangtextmark.cpp b/src/plugins/clangcodemodel/clangtextmark.cpp index 6120e90e917..c9c33dc5959 100644 --- a/src/plugins/clangcodemodel/clangtextmark.cpp +++ b/src/plugins/clangcodemodel/clangtextmark.cpp @@ -29,7 +29,6 @@ #include "clangdclient.h" #include "clangdiagnostictooltipwidget.h" #include "clangeditordocumentprocessor.h" -#include "clangmodelmanagersupport.h" #include "clangutils.h" #include @@ -42,12 +41,11 @@ #include #include +#include #include #include #include -#include -#include #include #include #include @@ -319,7 +317,7 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath, QObject::connect(action, &QAction::triggered, [diag = m_diagnostic]() { const QString text = ClangDiagnosticWidget::createText({diag}, ClangDiagnosticWidget::InfoBar); - QApplication::clipboard()->setText(text, QClipboard::Clipboard); + setClipboardAndSelection(text); }); actions << action; diff --git a/src/plugins/clangtools/clangtoolrunner.cpp b/src/plugins/clangtools/clangtoolrunner.cpp index c602203a24d..12fe0aede06 100644 --- a/src/plugins/clangtools/clangtoolrunner.cpp +++ b/src/plugins/clangtools/clangtoolrunner.cpp @@ -132,7 +132,7 @@ void ClangToolRunner::onProcessDone() 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(); + qCDebug(LOG).noquote() << "Output:\n" << m_process.cleanedStdOut(); emit finishedWithSuccess(m_fileToAnalyze); } else if (m_process.result() == ProcessResult::FinishedWithError) { emit finishedWithFailure(finishedWithBadExitCode(m_name, m_process.exitCode()), @@ -149,7 +149,7 @@ QString ClangToolRunner::commandlineAndOutput() const "Output:\n%3") .arg(m_commandLine.toUserOutput()) .arg(m_process.error()) - .arg(m_process.stdOut()); + .arg(m_process.cleanedStdOut()); } } // namespace Internal diff --git a/src/plugins/clangtools/diagnosticmark.cpp b/src/plugins/clangtools/diagnosticmark.cpp index 632781c7127..37dd7693921 100644 --- a/src/plugins/clangtools/diagnosticmark.cpp +++ b/src/plugins/clangtools/diagnosticmark.cpp @@ -30,10 +30,9 @@ #include "diagnosticconfigswidget.h" #include +#include #include -#include -#include namespace ClangTools { namespace Internal { @@ -65,7 +64,7 @@ DiagnosticMark::DiagnosticMark(const Diagnostic &diagnostic) const QString text = createFullLocationString(diagnostic.location) + ": " + diagnostic.description; - QApplication::clipboard()->setText(text); + Utils::setClipboardAndSelection(text); }); actions << action; diff --git a/src/plugins/clangtools/documentclangtoolrunner.cpp b/src/plugins/clangtools/documentclangtoolrunner.cpp index 28a4d0df29b..9b8b206f2cc 100644 --- a/src/plugins/clangtools/documentclangtoolrunner.cpp +++ b/src/plugins/clangtools/documentclangtoolrunner.cpp @@ -251,6 +251,8 @@ QPair getClangIncludeDirAndVersion(ClangToolRunner *runner) void DocumentClangToolRunner::runNext() { + if (m_currentRunner) + m_currentRunner.release()->deleteLater(); m_currentRunner.reset(m_runnerCreators.isEmpty() ? nullptr : m_runnerCreators.takeFirst()()); if (m_currentRunner) { auto [clangIncludeDir, clangVersion] = getClangIncludeDirAndVersion(m_currentRunner.get()); @@ -362,10 +364,7 @@ void DocumentClangToolRunner::cancel() if (m_projectSettingsUpdate) disconnect(m_projectSettingsUpdate); m_runnerCreators.clear(); - if (m_currentRunner) { - m_currentRunner->disconnect(this); - m_currentRunner.reset(nullptr); - } + m_currentRunner.reset(nullptr); } bool DocumentClangToolRunner::isSuppressed(const Diagnostic &diagnostic) const diff --git a/src/plugins/clangtools/executableinfo.cpp b/src/plugins/clangtools/executableinfo.cpp index 9277e54df9f..f27d4aef8b5 100644 --- a/src/plugins/clangtools/executableinfo.cpp +++ b/src/plugins/clangtools/executableinfo.cpp @@ -63,7 +63,7 @@ static QString runExecutable(const Utils::CommandLine &commandLine, QueryFailMod return {}; } - return cpp.stdOut(); + return cpp.cleanedStdOut(); } static QStringList queryClangTidyChecks(const FilePath &executable, diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index bd6786ed49c..7450ad9ff76 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -1676,8 +1676,8 @@ ClearCasePluginPrivate::runCleartool(const FilePath &workingDir, response.error = proc.result() != ProcessResult::FinishedWithSuccess; if (response.error) response.message = proc.exitMessage(); - response.stdErr = proc.stdErr(); - response.stdOut = proc.stdOut(); + response.stdErr = proc.cleanedStdErr(); + response.stdOut = proc.cleanedStdOut(); return response; } diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 482c2d05a38..c5804f039b8 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -280,19 +280,19 @@ TextEditor::Keywords CMakeTool::keywords() QtcProcess proc; runCMake(proc, {"--help-command-list"}, 5); if (proc.result() == ProcessResult::FinishedWithSuccess) - m_introspection->m_functions = proc.stdOut().split('\n'); + m_introspection->m_functions = proc.cleanedStdOut().split('\n'); runCMake(proc, {"--help-commands"}, 5); if (proc.result() == ProcessResult::FinishedWithSuccess) - parseFunctionDetailsOutput(proc.stdOut()); + parseFunctionDetailsOutput(proc.cleanedStdOut()); runCMake(proc, {"--help-property-list"}, 5); if (proc.result() == ProcessResult::FinishedWithSuccess) - m_introspection->m_variables = parseVariableOutput(proc.stdOut()); + m_introspection->m_variables = parseVariableOutput(proc.cleanedStdOut()); runCMake(proc, {"--help-variable-list"}, 5); if (proc.result() == ProcessResult::FinishedWithSuccess) { - m_introspection->m_variables.append(parseVariableOutput(proc.stdOut())); + m_introspection->m_variables.append(parseVariableOutput(proc.cleanedStdOut())); m_introspection->m_variables = Utils::filteredUnique(m_introspection->m_variables); Utils::sort(m_introspection->m_variables); } @@ -523,7 +523,7 @@ void CMakeTool::fetchFromCapabilities() const if (cmake.result() == ProcessResult::FinishedWithSuccess) { m_introspection->m_didRun = true; - parseFromCapabilities(cmake.stdOut()); + parseFromCapabilities(cmake.cleanedStdOut()); } else { qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << cmake.allOutput() << cmake.error(); m_introspection->m_didRun = false; diff --git a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp index 21d056f6083..9970fc019c4 100644 --- a/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp +++ b/src/plugins/cmakeprojectmanager/fileapidataextractor.cpp @@ -402,18 +402,18 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, const bool hasPchSource = anyOf(sources, [buildDirectory](const QString &path) { return isPchFile(buildDirectory, FilePath::fromString(path)); }); - if (!hasPchSource) { - QString headerMimeType; - if (ci.language == "C") - headerMimeType = CppEditor::Constants::C_HEADER_MIMETYPE; - else if (ci.language == "CXX") - headerMimeType = CppEditor::Constants::CPP_HEADER_MIMETYPE; + QString headerMimeType; + if (ci.language == "C") + headerMimeType = CppEditor::Constants::C_HEADER_MIMETYPE; + else if (ci.language == "CXX") + headerMimeType = CppEditor::Constants::CPP_HEADER_MIMETYPE; + if (!hasPchSource) { for (const SourceInfo &si : t.sources) { if (si.isGenerated) continue; const auto mimeTypes = Utils::mimeTypesForFileName(si.path); - for (auto mime : mimeTypes) + for (const auto &mime : mimeTypes) if (mime.name() == headerMimeType) sources.push_back(sourceDir.absoluteFilePath(si.path)); } @@ -421,8 +421,14 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input, // Set project files except pch files rpp.setFiles(Utils::filtered(sources, [buildDirectory](const QString &path) { - return !isPchFile(buildDirectory, FilePath::fromString(path)); - })); + return !isPchFile(buildDirectory, FilePath::fromString(path)); + }), {}, [headerMimeType](const QString &path) { + // Similar to ProjectFile::classify but classify headers with language + // of compile group instead of ambiguous header + if (path.endsWith(".h")) + return headerMimeType; + return Utils::mimeTypeForFile(path).name(); + }); FilePath precompiled_header = FilePath::fromString(findOrDefault(t.sources, [&ending](const SourceInfo &si) { diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp index 113e60ad740..17840e92544 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabasetests.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -239,13 +240,15 @@ void CompilationDatabaseTests::testFilterCommand() "SemaCodeComplete"); testData.getFilteredFlags(); - QCOMPARE(testData.flags, - (QStringList{"/Zc:inline", "/Zc:strictStrings", "/Zc:rvalueCast", "/Zi"})); - QCOMPARE(testData.headerPaths, - toUserHeaderPaths(QStringList{"C:/build-qt_llvm-msvc2017_64bit-Debug/tools\\clang\\lib\\Sema"})); - QCOMPARE(testData.macros, (Macros{{"UNICODE", "1"}, {"_HAS_EXCEPTIONS", "0"}, {"WIN32", "1"}, - {"_WINDOWS", "1"}})); - QCOMPARE(testData.fileKind, CppEditor::ProjectFile::Kind::CXXSource); + if (Utils::HostOsInfo::isWindowsHost()) { + QCOMPARE(testData.flags, + (QStringList{"/Zc:inline", "/Zc:strictStrings", "/Zc:rvalueCast", "/Zi"})); + QCOMPARE(testData.headerPaths, + toUserHeaderPaths(QStringList{"C:/build-qt_llvm-msvc2017_64bit-Debug/tools\\clang\\lib\\Sema"})); + QCOMPARE(testData.macros, (Macros{{"UNICODE", "1"}, {"_HAS_EXCEPTIONS", "0"}, {"WIN32", "1"}, + {"_WINDOWS", "1"}})); + QCOMPARE(testData.fileKind, CppEditor::ProjectFile::Kind::CXXSource); + } } void CompilationDatabaseTests::testFileKindDifferentFromExtension() diff --git a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp index b17b2c3a0e5..632db825562 100644 --- a/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp +++ b/src/plugins/compilationdatabaseprojectmanager/compilationdatabaseutils.cpp @@ -206,7 +206,7 @@ void filteredFlags(const QString &fileName, } // Skip all remaining Windows flags except feature flags. - if (flag.startsWith("/") && !flag.startsWith("/Z")) + if (Utils::HostOsInfo::isWindowsHost() && flag.startsWith("/") && !flag.startsWith("/Z")) continue; filtered.push_back(flag); diff --git a/src/plugins/coreplugin/documentmanager.cpp b/src/plugins/coreplugin/documentmanager.cpp index 12ad4c3e60e..789374133cf 100644 --- a/src/plugins/coreplugin/documentmanager.cpp +++ b/src/plugins/coreplugin/documentmanager.cpp @@ -830,8 +830,7 @@ FilePath DocumentManager::getSaveFileName(const QString &title, const FilePath & bool repeat; do { repeat = false; - filePath = FileUtils::getSaveFilePath(nullptr, title, path, filter, selectedFilter, - QFileDialog::DontConfirmOverwrite); + filePath = FileUtils::getSaveFilePath(nullptr, title, path, filter, selectedFilter); if (!filePath.isEmpty()) { // If the selected filter is All Files (*) we leave the name exactly as the user // specified. Otherwise the suffix must be one available in the selected filter. If @@ -852,18 +851,20 @@ FilePath DocumentManager::getSaveFileName(const QString &title, const FilePath & suffixOk = true; break; } - if (!suffixOk && !suffixes.isEmpty()) + if (!suffixOk && !suffixes.isEmpty()) { filePath = filePath.stringAppended(suffixes.at(0)); + if (filePath.exists()) { + if (QMessageBox::warning(ICore::dialogParent(), tr("Overwrite?"), + tr("An item named \"%1\" already exists at this location. " + "Do you want to overwrite it?").arg(filePath.toUserOutput()), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { + repeat = true; + } + } + } } } - if (filePath.exists()) { - if (QMessageBox::warning(ICore::dialogParent(), tr("Overwrite?"), - tr("An item named \"%1\" already exists at this location. " - "Do you want to overwrite it?").arg(filePath.toUserOutput()), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) { - repeat = true; - } - } + } } while (repeat); if (!filePath.isEmpty()) diff --git a/src/plugins/coreplugin/locator/executefilter.cpp b/src/plugins/coreplugin/locator/executefilter.cpp index 59d6d7a3212..fe54059efc8 100644 --- a/src/plugins/coreplugin/locator/executefilter.cpp +++ b/src/plugins/coreplugin/locator/executefilter.cpp @@ -132,16 +132,10 @@ void ExecuteFilter::accept(const LocatorFilterEntry &selection, p->runHeadCommand(); } -void ExecuteFilter::finished() +void ExecuteFilter::done() { QTC_ASSERT(m_process, return); - const QString commandName = headCommand(); - QString message; - if (m_process->result() == ProcessResult::FinishedWithSuccess) - message = tr("Command \"%1\" finished.").arg(commandName); - else - message = tr("Command \"%1\" failed.").arg(commandName); - MessageManager::writeFlashing(message); + MessageManager::writeFlashing(m_process->exitMessage()); removeProcess(); runHeadCommand(); @@ -180,12 +174,6 @@ void ExecuteFilter::runHeadCommand() m_process->setWorkingDirectory(d.workingDirectory); m_process->setCommand(d.command); m_process->start(); - if (!m_process->waitForStarted(1000)) { - MessageManager::writeFlashing( - tr("Could not start process: %1.").arg(m_process->errorString())); - removeProcess(); - runHeadCommand(); - } } } @@ -196,7 +184,7 @@ void ExecuteFilter::createProcess() m_process = new Utils::QtcProcess; m_process->setEnvironment(Utils::Environment::systemEnvironment()); - connect(m_process, &QtcProcess::finished, this, &ExecuteFilter::finished); + connect(m_process, &QtcProcess::done, this, &ExecuteFilter::done); connect(m_process, &QtcProcess::readyReadStandardOutput, this, &ExecuteFilter::readStandardOutput); connect(m_process, &QtcProcess::readyReadStandardError, this, &ExecuteFilter::readStandardError); } @@ -207,7 +195,7 @@ void ExecuteFilter::removeProcess() return; m_taskQueue.dequeue(); - delete m_process; + m_process->deleteLater(); m_process = nullptr; } diff --git a/src/plugins/coreplugin/locator/executefilter.h b/src/plugins/coreplugin/locator/executefilter.h index 588bdad6ecd..7da5c086753 100644 --- a/src/plugins/coreplugin/locator/executefilter.h +++ b/src/plugins/coreplugin/locator/executefilter.h @@ -57,7 +57,7 @@ public: QString *newText, int *selectionStart, int *selectionLength) const override; private: - void finished(); + void done(); void readStandardOutput(); void readStandardError(); void runHeadCommand(); diff --git a/src/plugins/cppcheck/cppcheckrunner.cpp b/src/plugins/cppcheck/cppcheckrunner.cpp index 4e4e3d40524..542631beb71 100644 --- a/src/plugins/cppcheck/cppcheckrunner.cpp +++ b/src/plugins/cppcheck/cppcheckrunner.cpp @@ -28,7 +28,6 @@ #include #include -#include #include @@ -37,11 +36,9 @@ using namespace Utils; namespace Cppcheck { namespace Internal { -CppcheckRunner::CppcheckRunner(CppcheckTool &tool) : - m_tool(tool), - m_process(new Utils::QtcProcess(this)) +CppcheckRunner::CppcheckRunner(CppcheckTool &tool) : m_tool(tool) { - if (Utils::HostOsInfo::hostOs() == Utils::OsTypeLinux) { + if (HostOsInfo::hostOs() == OsTypeLinux) { QtcProcess getConf; getConf.setCommand({"getconf", {"ARG_MAX"}}); getConf.start(); @@ -50,17 +47,15 @@ CppcheckRunner::CppcheckRunner(CppcheckTool &tool) : m_maxArgumentsLength = std::max(argMax.toInt(), m_maxArgumentsLength); } - m_process->setStdOutLineCallback([this](const QString &line) { + m_process.setStdOutLineCallback([this](const QString &line) { m_tool.parseOutputLine(line); }); - m_process->setStdErrLineCallback([this](const QString &line) { + m_process.setStdErrLineCallback([this](const QString &line) { m_tool.parseErrorLine(line); }); - connect(m_process, &QtcProcess::started, - this, &CppcheckRunner::handleStarted); - connect(m_process, &QtcProcess::finished, - this, &CppcheckRunner::handleFinished); + connect(&m_process, &QtcProcess::started, &m_tool, &CppcheckTool::startParsing); + connect(&m_process, &QtcProcess::done, this, &CppcheckRunner::handleDone); m_queueTimer.setSingleShot(true); const int checkDelayInMs = 200; @@ -81,18 +76,18 @@ void CppcheckRunner::reconfigure(const FilePath &binary, const QString &argument m_arguments = arguments; } -void CppcheckRunner::addToQueue(const Utils::FilePaths &files, +void CppcheckRunner::addToQueue(const FilePaths &files, const QString &additionalArguments) { - Utils::FilePaths &existing = m_queue[additionalArguments]; + FilePaths &existing = m_queue[additionalArguments]; if (existing.isEmpty()) { existing = files; } else { std::copy_if(files.cbegin(), files.cend(), std::back_inserter(existing), - [&existing](const Utils::FilePath &file) { return !existing.contains(file); }); + [&existing](const FilePath &file) { return !existing.contains(file); }); } - if (m_isRunning) { + if (m_process.isRunning()) { stop(existing); return; } @@ -100,16 +95,16 @@ void CppcheckRunner::addToQueue(const Utils::FilePaths &files, m_queueTimer.start(); } -void CppcheckRunner::stop(const Utils::FilePaths &files) +void CppcheckRunner::stop(const FilePaths &files) { - if (!m_isRunning) + if (!m_process.isRunning()) return; if (files.isEmpty() || m_currentFiles == files) - m_process->kill(); + m_process.stop(); } -void CppcheckRunner::removeFromQueue(const Utils::FilePaths &files) +void CppcheckRunner::removeFromQueue(const FilePaths &files) { if (m_queue.isEmpty()) return; @@ -118,21 +113,21 @@ void CppcheckRunner::removeFromQueue(const Utils::FilePaths &files) m_queue.clear(); } else { for (auto it = m_queue.begin(), end = m_queue.end(); it != end;) { - for (const Utils::FilePath &file : files) + for (const FilePath &file : files) it.value().removeOne(file); it = !it.value().isEmpty() ? ++it : m_queue.erase(it); } } } -const Utils::FilePaths &CppcheckRunner::currentFiles() const +const FilePaths &CppcheckRunner::currentFiles() const { return m_currentFiles; } QString CppcheckRunner::currentCommand() const { - return m_process->commandLine().toUserOutput(); + return m_process.commandLine().toUserOutput(); } void CppcheckRunner::checkQueued() @@ -140,7 +135,7 @@ void CppcheckRunner::checkQueued() if (m_queue.isEmpty() || m_binary.isEmpty()) return; - Utils::FilePaths files = m_queue.begin().value(); + FilePaths files = m_queue.begin().value(); QString arguments = m_arguments + ' ' + m_queue.begin().key(); m_currentFiles.clear(); int argumentsLength = arguments.length(); @@ -158,30 +153,19 @@ void CppcheckRunner::checkQueued() else m_queue.begin().value() = files; - m_process->setCommand(CommandLine(m_binary, arguments, CommandLine::Raw)); - m_process->start(); + m_process.setCommand(CommandLine(m_binary, arguments, CommandLine::Raw)); + m_process.start(); } -void CppcheckRunner::handleStarted() +void CppcheckRunner::handleDone() { - if (m_isRunning) - return; - - m_isRunning = true; - m_tool.startParsing(); -} - -void CppcheckRunner::handleFinished() -{ - if (m_process->error() != QProcess::FailedToStart) { + if (m_process.result() == ProcessResult::FinishedWithSuccess) m_tool.finishParsing(); - } else { - const QString message = tr("Cppcheck failed to start: \"%1\".").arg(currentCommand()); - Core::MessageManager::writeSilently(message); - } + else + Core::MessageManager::writeSilently(m_process.exitMessage()); + m_currentFiles.clear(); - m_process->close(); - m_isRunning = false; + m_process.close(); if (!m_queue.isEmpty()) checkQueued(); diff --git a/src/plugins/cppcheck/cppcheckrunner.h b/src/plugins/cppcheck/cppcheckrunner.h index d49a9016dea..d35943b31f0 100644 --- a/src/plugins/cppcheck/cppcheckrunner.h +++ b/src/plugins/cppcheck/cppcheckrunner.h @@ -26,12 +26,11 @@ #pragma once #include +#include #include #include -namespace Utils { class QtcProcess; } - namespace Cppcheck { namespace Internal { @@ -58,18 +57,16 @@ private: void checkQueued(); void readOutput(); void readError(); - void handleStarted(); - void handleFinished(); + void handleDone(); CppcheckTool &m_tool; - Utils::QtcProcess *m_process = nullptr; + Utils::QtcProcess m_process; Utils::FilePath m_binary; QString m_arguments; QHash m_queue; Utils::FilePaths m_currentFiles; QTimer m_queueTimer; int m_maxArgumentsLength = 32767; - bool m_isRunning = false; }; } // namespace Internal diff --git a/src/plugins/cppeditor/cppcodemodelsettings.cpp b/src/plugins/cppeditor/cppcodemodelsettings.cpp index 0c59d923c25..69f61e2e549 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.cpp +++ b/src/plugins/cppeditor/cppcodemodelsettings.cpp @@ -34,6 +34,7 @@ #include #include +#include #include #include #include @@ -81,6 +82,7 @@ static QString clangdSizeThresholdKey() { return QLatin1String("ClangdSizeThresh static QString clangdUseGlobalSettingsKey() { return QLatin1String("useGlobalSettings"); } static QString sessionsWithOneClangdKey() { return QLatin1String("SessionsWithOneClangd"); } static QString diagnosticConfigIdKey() { return QLatin1String("diagnosticConfigId"); } +static QString checkedHardwareKey() { return QLatin1String("checkedHardware"); } static FilePath g_defaultClangdFilePath; static FilePath fallbackClangdFilePath() @@ -206,6 +208,22 @@ bool ClangdSettings::useClangd() const return m_data.useClangd && clangdVersion() >= QVersionNumber(14); } +void ClangdSettings::setUseClangd(bool use) { instance().m_data.useClangd = use; } + +bool ClangdSettings::hardwareFulfillsRequirements() +{ + instance().m_data.haveCheckedHardwareReqirements = true; + instance().saveSettings(); + const quint64 minRam = quint64(12) * 1024 * 1024 * 1024; + const Utils::optional totalRam = Utils::HostOsInfo::totalMemoryInstalledInBytes(); + return !totalRam || *totalRam >= minRam; +} + +bool ClangdSettings::haveCheckedHardwareRequirements() +{ + return instance().data().haveCheckedHardwareReqirements; +} + void ClangdSettings::setDefaultClangdPath(const FilePath &filePath) { g_defaultClangdFilePath = filePath; @@ -350,8 +368,6 @@ void ClangdSettings::saveSettings() } #ifdef WITH_TESTS -void ClangdSettings::setUseClangd(bool use) { instance().m_data.useClangd = use; } - void ClangdSettings::setClangdFilePath(const FilePath &filePath) { instance().m_data.executableFilePath = filePath; @@ -435,6 +451,7 @@ QVariantMap ClangdSettings::Data::toMap() const map.insert(clangdSizeThresholdKey(), sizeThresholdInKb); map.insert(sessionsWithOneClangdKey(), sessionsWithOneClangd); map.insert(diagnosticConfigIdKey(), diagnosticConfigId.toSetting()); + map.insert(checkedHardwareKey(), true); return map; } @@ -451,6 +468,7 @@ void ClangdSettings::Data::fromMap(const QVariantMap &map) sessionsWithOneClangd = map.value(sessionsWithOneClangdKey()).toStringList(); diagnosticConfigId = Id::fromSetting(map.value(diagnosticConfigIdKey(), initialClangDiagnosticConfigId().toSetting())); + haveCheckedHardwareReqirements = map.value(checkedHardwareKey(), false).toBool(); } } // namespace CppEditor diff --git a/src/plugins/cppeditor/cppcodemodelsettings.h b/src/plugins/cppeditor/cppcodemodelsettings.h index 1bf5b46616a..8cf0bac463c 100644 --- a/src/plugins/cppeditor/cppcodemodelsettings.h +++ b/src/plugins/cppeditor/cppcodemodelsettings.h @@ -111,7 +111,8 @@ public: && s1.autoIncludeHeaders == s2.autoIncludeHeaders && s1.documentUpdateThreshold == s2.documentUpdateThreshold && s1.sizeThresholdEnabled == s2.sizeThresholdEnabled - && s1.sizeThresholdInKb == s2.sizeThresholdInKb; + && s1.sizeThresholdInKb == s2.sizeThresholdInKb + && s1.haveCheckedHardwareReqirements == s2.haveCheckedHardwareReqirements; } friend bool operator!=(const Data &s1, const Data &s2) { return !(s1 == s2); } @@ -126,12 +127,17 @@ public: bool enableIndexing = true; bool autoIncludeHeaders = false; bool sizeThresholdEnabled = false; + bool haveCheckedHardwareReqirements = false; }; ClangdSettings(const Data &data) : m_data(data) {} static ClangdSettings &instance(); bool useClangd() const; + static void setUseClangd(bool use); + + static bool hardwareFulfillsRequirements(); + static bool haveCheckedHardwareRequirements(); static void setDefaultClangdPath(const Utils::FilePath &filePath); static void setCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs); @@ -159,7 +165,6 @@ public: static Utils::FilePath clangdUserConfigFilePath(); #ifdef WITH_TESTS - static void setUseClangd(bool use); static void setClangdFilePath(const Utils::FilePath &filePath); #endif diff --git a/src/plugins/cppeditor/cppcodestylesnippets.h b/src/plugins/cppeditor/cppcodestylesnippets.h index d58a728f233..83cb3555d54 100644 --- a/src/plugins/cppeditor/cppcodestylesnippets.h +++ b/src/plugins/cppeditor/cppcodestylesnippets.h @@ -135,6 +135,12 @@ static const char *DEFAULT_CODE_STYLE_SNIPPETS[] "private:\n" " int _a;\n" " };\n" + "enum class E\n" + "{\n" + " V1,\n" + " V2,\n" + " V3\n" + "};\n" "}\n" "}\n", "#include \"bar.h\"\n" diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index e7621e823ee..80a8cce0bd3 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -50,7 +50,9 @@ #include #include #include +#include +#include #include const char NO_PROJECT_CONFIGURATION[] = "NoProject"; @@ -121,6 +123,9 @@ CppEditorDocument::CppEditorDocument() connect(this, &IDocument::filePathChanged, this, &CppEditorDocument::onFilePathChanged); + connect(mm(), &CppModelManager::diagnosticsChanged, + this, &CppEditorDocument::onDiagnosticsChanged); + connect(&m_parseContextModel, &ParseContextModel::preferredParseContextChanged, this, &CppEditorDocument::reparseWithPreferredParseContext); @@ -483,5 +488,51 @@ bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, boo return TextEditor::TextDocument::save(errorString, filePath, autoSave); } +void CppEditorDocument::onDiagnosticsChanged(const QString &fileName, const QString &kind) +{ + if (FilePath::fromString(fileName) != filePath()) + return; + + TextMarks removedMarks = marks(); + + const Utils::Id category = Utils::Id::fromString(kind); + + for (const auto &diagnostic : mm()->diagnosticMessages()) { + if (FilePath::fromString(diagnostic.fileName()) == filePath()) { + auto it = std::find_if(std::begin(removedMarks), + std::end(removedMarks), + [&category, &diagnostic](TextMark *existing) { + return (diagnostic.line() == existing->lineNumber() + && diagnostic.text() == existing->lineAnnotation() + && category == existing->category()); + }); + + if (it != std::end(removedMarks)) { + removedMarks.erase(it); + continue; + } + + auto mark = new TextMark(filePath(), diagnostic.line(), category); + mark->setLineAnnotation(diagnostic.text()); + mark->setToolTip(diagnostic.text()); + + mark->setIcon(diagnostic.isWarning() ? Utils::Icons::CODEMODEL_WARNING.icon() + : Utils::Icons::CODEMODEL_ERROR.icon()); + mark->setColor(diagnostic.isWarning() ? Utils::Theme::CodeModel_Warning_TextMarkColor + : Utils::Theme::CodeModel_Error_TextMarkColor); + mark->setPriority(diagnostic.isWarning() ? TextEditor::TextMark::NormalPriority + : TextEditor::TextMark::HighPriority); + addMark(mark); + } + } + + for (auto it = removedMarks.begin(); it != removedMarks.end(); ++it) { + if ((*it)->category() == category) { + removeMark(*it); + delete *it; + } + } +} + } // namespace Internal } // namespace CppEditor diff --git a/src/plugins/cppeditor/cppeditordocument.h b/src/plugins/cppeditor/cppeditordocument.h index 54009a04ebd..09d5ab96b63 100644 --- a/src/plugins/cppeditor/cppeditordocument.h +++ b/src/plugins/cppeditor/cppeditordocument.h @@ -94,6 +94,8 @@ private: void onAboutToReload(); void onReloadFinished(); + void onDiagnosticsChanged(const QString &fileName, const QString &kind); + void reparseWithPreferredParseContext(const QString &id); diff --git a/src/plugins/cppeditor/cppmodelmanager.cpp b/src/plugins/cppeditor/cppmodelmanager.cpp index f646631a90e..7bbf588383f 100644 --- a/src/plugins/cppeditor/cppmodelmanager.cpp +++ b/src/plugins/cppeditor/cppmodelmanager.cpp @@ -201,6 +201,8 @@ public: std::unique_ptr m_functionsFilter; std::unique_ptr m_symbolsFindFilter; std::unique_ptr m_currentDocumentFilter; + + QList m_diagnosticMessages; }; } // namespace Internal @@ -1704,4 +1706,18 @@ QThreadPool *CppModelManager::sharedThreadPool() return &d->m_threadPool; } +bool CppModelManager::setExtraDiagnostics(const QString &fileName, + const QString &kind, + const QList &diagnostics) +{ + d->m_diagnosticMessages = diagnostics; + emit diagnosticsChanged(fileName, kind); + return true; +} + +const QList CppModelManager::diagnosticMessages() +{ + return d->m_diagnosticMessages; +} + } // namespace CppEditor diff --git a/src/plugins/cppeditor/cppmodelmanager.h b/src/plugins/cppeditor/cppmodelmanager.h index 3526bb5fbe0..efccd521190 100644 --- a/src/plugins/cppeditor/cppmodelmanager.h +++ b/src/plugins/cppeditor/cppmodelmanager.h @@ -104,6 +104,12 @@ public: QByteArray codeModelConfiguration() const; CppLocatorData *locatorData() const; + bool setExtraDiagnostics(const QString &fileName, + const QString &kind, + const QList &diagnostics) override; + + const QList diagnosticMessages(); + QList projectInfos() const; ProjectInfo::ConstPtr projectInfo(ProjectExplorer::Project *project) const; QFuture updateProjectInfo(const ProjectInfo::ConstPtr &newProjectInfo, @@ -256,6 +262,8 @@ signals: void abstractEditorSupportRemoved(const QString &filePath); void fallbackProjectPartUpdated(); + void diagnosticsChanged(const QString &fileName, const QString &kind); + public slots: void updateModifiedSourceFiles(); void GC(); diff --git a/src/plugins/cppeditor/cppprojectinfogenerator.cpp b/src/plugins/cppeditor/cppprojectinfogenerator.cpp index 67ebd19f6d5..55bbf3d3560 100644 --- a/src/plugins/cppeditor/cppprojectinfogenerator.cpp +++ b/src/plugins/cppeditor/cppprojectinfogenerator.cpp @@ -87,7 +87,8 @@ const QVector ProjectInfoGenerator::createProjectParts( QVector result; ProjectFileCategorizer cat(rawProjectPart.displayName, rawProjectPart.files, - rawProjectPart.fileIsActive); + rawProjectPart.fileIsActive, + rawProjectPart.getMimeType); if (!cat.hasParts()) return result; diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 8b3210a9e0a..e004f6cd886 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -1449,8 +1449,8 @@ CvsResponse CvsPluginPrivate::runCvs(const FilePath &workingDirectory, command.runCommand(proc, {executable, m_settings.addOptions(arguments)}); response.result = CvsResponse::OtherError; - response.stdErr = proc.stdErr(); - response.stdOut = proc.stdOut(); + response.stdErr = proc.cleanedStdErr(); + response.stdOut = proc.cleanedStdOut(); switch (proc.result()) { case ProcessResult::FinishedWithSuccess: response.result = CvsResponse::Ok; diff --git a/src/plugins/debugger/analyzer/detailederrorview.cpp b/src/plugins/debugger/analyzer/detailederrorview.cpp index a5fad37821f..b1ac155afb2 100644 --- a/src/plugins/debugger/analyzer/detailederrorview.cpp +++ b/src/plugins/debugger/analyzer/detailederrorview.cpp @@ -30,12 +30,12 @@ #include #include +#include #include +#include #include #include -#include -#include #include #include #include @@ -54,12 +54,12 @@ DetailedErrorView::DetailedErrorView(QWidget *parent) : m_copyAction->setIcon(Utils::Icons::COPY.icon()); m_copyAction->setShortcut(QKeySequence::Copy); m_copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); - connect(m_copyAction, &QAction::triggered, [this] { + connect(m_copyAction, &QAction::triggered, this, [this] { const QModelIndexList selectedRows = selectionModel()->selectedRows(); QStringList data; for (const QModelIndex &index : selectedRows) data << model()->data(index, FullTextRole).toString(); - QApplication::clipboard()->setText(data.join('\n')); + Utils::setClipboardAndSelection(data.join('\n')); }); connect(this, &QAbstractItemView::clicked, [](const QModelIndex &index) { if (index.column() == LocationColumn) { diff --git a/src/plugins/debugger/cdb/cdbengine.cpp b/src/plugins/debugger/cdb/cdbengine.cpp index e3602fba712..ce6ffac2564 100644 --- a/src/plugins/debugger/cdb/cdbengine.cpp +++ b/src/plugins/debugger/cdb/cdbengine.cpp @@ -56,6 +56,7 @@ #include #include +#include #include #include #include @@ -211,8 +212,8 @@ CdbEngine::CdbEngine() : DebuggerSettings *s = debuggerSettings(); connect(s->createFullBacktrace.action(), &QAction::triggered, this, &CdbEngine::createFullBacktrace); - connect(&m_process, &QtcProcess::finished, this, &CdbEngine::processFinished); - connect(&m_process, &QtcProcess::errorOccurred, this, &CdbEngine::processError); + connect(&m_process, &QtcProcess::started, this, &CdbEngine::processStarted); + connect(&m_process, &QtcProcess::done, this, &CdbEngine::processDone); connect(&m_process, &QtcProcess::readyReadStandardOutput, this, &CdbEngine::readyReadStandardOut); connect(&m_process, &QtcProcess::readyReadStandardError, @@ -291,14 +292,13 @@ bool CdbEngine::canHandleToolTip(const DebuggerToolTipContext &context) const } // Determine full path to the CDB extension library. -QString CdbEngine::extensionLibraryName(bool is64Bit) +QString CdbEngine::extensionLibraryName(bool is64Bit, bool isArm) { // Determine extension lib name and path to use - QString rc; - QTextStream(&rc) << QFileInfo(QCoreApplication::applicationDirPath()).path() - << "/lib/" << (is64Bit ? QT_CREATOR_CDB_EXT "64" : QT_CREATOR_CDB_EXT "32") - << '/' << QT_CREATOR_CDB_EXT << ".dll"; - return rc; + return QString("%1/lib/" QT_CREATOR_CDB_EXT "%2%3/" QT_CREATOR_CDB_EXT ".dll") + .arg(QFileInfo(QCoreApplication::applicationDirPath()).path()) + .arg(isArm ? "arm" : QString()) + .arg(is64Bit ? "64": "32"); } int CdbEngine::elapsedLogTime() @@ -354,10 +354,17 @@ void CdbEngine::setupEngine() return; } - bool cdbIs64Bit = Utils::is64BitWindowsBinary(sp.debugger.command.executable()); - if (!cdbIs64Bit) + bool cdbIs64Bit = true; + bool cdbIsArm = false; + Abis abisOfCdb = Abi::abisOfBinary(sp.debugger.command.executable()); + if (abisOfCdb.size() == 1) { + Abi abi = abisOfCdb.at(0); + cdbIs64Bit = abi.wordWidth() == 64; + cdbIsArm = abi.architecture() == Abi::Architecture::ArmArchitecture; + } + if (!cdbIs64Bit || cdbIsArm) m_wow64State = noWow64Stack; - const QFileInfo extensionFi(CdbEngine::extensionLibraryName(cdbIs64Bit)); + const QFileInfo extensionFi(CdbEngine::extensionLibraryName(cdbIs64Bit, cdbIsArm)); if (!extensionFi.isFile()) { handleSetupFailure(tr("Internal error: The extension %1 cannot be found.\n" "If you have updated %2 via Maintenance Tool, you may " @@ -376,12 +383,12 @@ void CdbEngine::setupEngine() // Prepare command line. CommandLine debugger{sp.debugger.command}; - const QString extensionFileName = extensionFi.fileName(); + m_extensionFileName = extensionFi.fileName(); const bool isRemote = sp.startMode == AttachToRemoteServer; if (isRemote) { // Must be first debugger.addArgs({"-remote", sp.remoteChannel}); } else { - debugger.addArg("-a" + extensionFileName); + debugger.addArg("-a" + m_extensionFileName); } // Source line info/No terminal breakpoint / Pull extension @@ -463,20 +470,19 @@ void CdbEngine::setupEngine() m_process.setCommand(debugger); m_process.start(); - if (!m_process.waitForStarted()) { - handleSetupFailure(QString("Internal error: Cannot start process %1: %2"). - arg(debugger.toUserOutput(), m_process.errorString())); - return; - } +} +void CdbEngine::processStarted() +{ const qint64 pid = m_process.processId(); - showMessage(QString("%1 running as %2").arg(debugger.executable().toUserOutput()).arg(pid), - LogMisc); + const FilePath execPath = runParameters().debugger.command.executable(); + showMessage(QString("%1 running as %2").arg(execPath.toUserOutput()).arg(pid), LogMisc); m_hasDebuggee = true; m_initialSessionIdleHandled = false; - if (isRemote) { // We do not get an 'idle' in a remote session, but are accessible + if (runParameters().startMode == AttachToRemoteServer) { + // We do not get an 'idle' in a remote session, but are accessible m_accessible = true; - runCommand({".load " + extensionFileName, NoFlags}); + runCommand({".load " + m_extensionFileName, NoFlags}); handleInitialSessionIdle(); } } @@ -702,12 +708,21 @@ void CdbEngine::abortDebuggerProcess() m_process.kill(); } -void CdbEngine::processFinished() +void CdbEngine::processDone() { - if (debug) + if (m_process.result() == ProcessResult::StartFailed) { + handleSetupFailure(m_process.exitMessage()); + return; + } + + if (m_process.error() != QProcess::UnknownError) + showMessage(m_process.errorString(), LogError); + + if (debug) { qDebug("CdbEngine::processFinished %dms '%s' (exit state=%d, ex=%d)", elapsedLogTime(), qPrintable(stateName(state())), m_process.exitStatus(), m_process.exitCode()); + } notifyDebuggerProcessFinished(m_process.resultData(), "CDB"); } @@ -1039,7 +1054,7 @@ void CdbEngine::runCommand(const DebuggerCommand &dbgCmd) QList splittedArguments; int maxArgumentSize = maxCommandLength - prefix.length() - maxTokenLength; while (argumentSplitPos < arguments.size()) { - splittedArguments << Utils::midView(arguments, argumentSplitPos, maxArgumentSize); + splittedArguments << midView(arguments, argumentSplitPos, maxArgumentSize); argumentSplitPos += splittedArguments.last().length(); } QTC_CHECK(argumentSplitPos == arguments.size()); @@ -2446,11 +2461,6 @@ void CdbEngine::readyReadStandardError() showMessage(QString::fromLocal8Bit(m_process.readAllStandardError()), LogError); } -void CdbEngine::processError() -{ - showMessage(m_process.errorString(), LogError); -} - #if 0 // Join breakpoint ids for a multi-breakpoint id commands like 'bc', 'be', 'bd' static QByteArray multiBreakpointCommand(const char *cmdC, const Breakpoints &bps) @@ -2498,14 +2508,14 @@ public: const CppEditor::WorkingCopy &workingCopy) : m_snapshot(s), m_workingCopy(workingCopy) {} - unsigned fixLineNumber(const Utils::FilePath &filePath, unsigned lineNumber) const; + unsigned fixLineNumber(const FilePath &filePath, unsigned lineNumber) const; private: const CPlusPlus::Snapshot m_snapshot; CppEditor::WorkingCopy m_workingCopy; }; -static CPlusPlus::Document::Ptr getParsedDocument(const Utils::FilePath &filePath, +static CPlusPlus::Document::Ptr getParsedDocument(const FilePath &filePath, const CppEditor::WorkingCopy &workingCopy, const CPlusPlus::Snapshot &snapshot) { @@ -2520,7 +2530,7 @@ static CPlusPlus::Document::Ptr getParsedDocument(const Utils::FilePath &filePat return doc; } -unsigned BreakpointCorrectionContext::fixLineNumber(const Utils::FilePath &filePath, +unsigned BreakpointCorrectionContext::fixLineNumber(const FilePath &filePath, unsigned lineNumber) const { const CPlusPlus::Document::Ptr doc = getParsedDocument(filePath, @@ -2677,7 +2687,7 @@ static StackFrames parseFrames(const GdbMi &gdbmi, bool *incomplete = nullptr) frame.level = QString::number(i); const GdbMi fullName = frameMi["fullname"]; if (fullName.isValid()) { - frame.file = Utils::FilePath::fromString(fullName.data()).normalizedPathName(); + frame.file = FilePath::fromString(fullName.data()).normalizedPathName(); frame.line = frameMi["line"].data().toInt(); frame.usable = false; // To be decided after source path mapping. const GdbMi languageMi = frameMi["language"]; diff --git a/src/plugins/debugger/cdb/cdbengine.h b/src/plugins/debugger/cdb/cdbengine.h index 811b539c000..1209d0ad3a7 100644 --- a/src/plugins/debugger/cdb/cdbengine.h +++ b/src/plugins/debugger/cdb/cdbengine.h @@ -101,13 +101,13 @@ public: void loadAdditionalQmlStack() override; void listBreakpoints(); - static QString extensionLibraryName(bool is64Bit); + static QString extensionLibraryName(bool is64Bit, bool isArm = false); private: void readyReadStandardOut(); void readyReadStandardError(); - void processError(); - void processFinished(); + void processStarted(); + void processDone(); void runCommand(const DebuggerCommand &cmd) override; void adjustOperateByInstruction(bool); @@ -223,6 +223,7 @@ private: wow64Stack64Bit } m_wow64State = wow64Uninitialized; QElapsedTimer m_logTimer; + QString m_extensionFileName; QString m_extensionMessageBuffer; bool m_sourceStepInto = false; int m_watchPointX = 0; diff --git a/src/plugins/debugger/console/consoleview.cpp b/src/plugins/debugger/console/consoleview.cpp index 93fec5b73e6..72ff8cedef8 100644 --- a/src/plugins/debugger/console/consoleview.cpp +++ b/src/plugins/debugger/console/consoleview.cpp @@ -30,14 +30,15 @@ #include #include #include + #include +#include #include #include #include #include #include -#include #include #include #include @@ -204,8 +205,7 @@ void ConsoleView::copyToClipboard(const QModelIndex &index) contents = QString::fromLatin1("%1 %2: %3").arg(contents).arg(filePath).arg( model()->data(index, ConsoleItem::LineRole).toString()); } - QClipboard *cb = QApplication::clipboard(); - cb->setText(contents); + Utils::setClipboardAndSelection(contents); } bool ConsoleView::canShowItemInTextEditor(const QModelIndex &index) diff --git a/src/plugins/debugger/debuggeritemmanager.cpp b/src/plugins/debugger/debuggeritemmanager.cpp index 4f0d4702589..9afc0877680 100644 --- a/src/plugins/debugger/debuggeritemmanager.cpp +++ b/src/plugins/debugger/debuggeritemmanager.cpp @@ -670,7 +670,7 @@ void DebuggerItemManagerPrivate::autoDetectCdbDebuggers() for (const QFileInfo &kitFolderFi : kitFolders) { const QString path = kitFolderFi.absoluteFilePath(); QStringList abis = {"x86", "x64"}; - if (HostOsInfo::hostArchitecture() == HostOsInfo::HostArchitectureArm) + if (HostOsInfo::hostArchitecture() == HostOsInfo::HostArchitectureArm64) abis << "arm64"; for (const QString &abi: abis) { const QFileInfo cdbBinary(path + "/Debuggers/" + abi + "/cdb.exe"); diff --git a/src/plugins/debugger/debuggertooltipmanager.cpp b/src/plugins/debugger/debuggertooltipmanager.cpp index 8a6eab069a1..4177879653c 100644 --- a/src/plugins/debugger/debuggertooltipmanager.cpp +++ b/src/plugins/debugger/debuggertooltipmanager.cpp @@ -26,7 +26,6 @@ #include "debuggertooltipmanager.h" #include "debuggeractions.h" -#include "debuggercore.h" #include "debuggerengine.h" #include "debuggerinternalconstants.h" #include "debuggermainwindow.h" @@ -34,7 +33,6 @@ #include "sourceutils.h" #include "stackhandler.h" #include "watchhandler.h" -#include "watchwindow.h" #include #include @@ -53,6 +51,7 @@ #include #include #include +#include #include #include @@ -577,17 +576,14 @@ DebuggerToolTipWidget::DebuggerToolTipWidget() mainLayout->addWidget(toolBar); mainLayout->addWidget(treeView); - connect(copyButton, &QAbstractButton::clicked, [this] { + connect(copyButton, &QAbstractButton::clicked, this, [this] { QString text; QTextStream str(&text); model.forAllItems([&str](ToolTipWatchItem *item) { str << QString(item->level(), '\t') << item->name << '\t' << item->value << '\t' << item->type << '\n'; }); - QClipboard *clipboard = QApplication::clipboard(); - if (clipboard->supportsSelection()) - clipboard->setText(text, QClipboard::Selection); - clipboard->setText(text, QClipboard::Clipboard); + setClipboardAndSelection(text); }); connect(treeView, &QTreeView::expanded, &model, &ToolTipModel::expandNode); diff --git a/src/plugins/debugger/gdb/gdbengine.cpp b/src/plugins/debugger/gdb/gdbengine.cpp index bf62f52c829..6dc3cb9d800 100644 --- a/src/plugins/debugger/gdb/gdbengine.cpp +++ b/src/plugins/debugger/gdb/gdbengine.cpp @@ -169,6 +169,8 @@ GdbEngine::GdbEngine() connect(&s.useDynamicType, &BaseAspect::changed, this, &GdbEngine::reloadLocals); + connect(&m_gdbProc, &QtcProcess::started, + this, &GdbEngine::handleGdbStarted); connect(&m_gdbProc, &QtcProcess::done, this, &GdbEngine::handleGdbDone); connect(&m_gdbProc, &QtcProcess::readyReadStandardOutput, @@ -3865,20 +3867,10 @@ void GdbEngine::setupEngine() m_gdbProc.setWorkingDirectory(rp.debugger.workingDirectory); m_gdbProc.setEnvironment(gdbEnv); m_gdbProc.start(); +} - if (!m_gdbProc.waitForStarted()) { - handleGdbStartFailed(); - QString msg; - FilePath wd = m_gdbProc.workingDirectory(); - if (!wd.isReadableDir()) - msg = failedToStartMessage() + ' ' + tr("The working directory \"%1\" is not usable.") - .arg(wd.toUserOutput()); - else - msg = RunWorker::userMessageForProcessError(QProcess::FailedToStart, rp.debugger.command.executable()); - handleAdapterStartFailed(msg); - return; - } - +void GdbEngine::handleGdbStarted() +{ showMessage("GDB STARTED, INITIALIZING IT"); runCommand({"show version", CB(handleShowVersion)}); runCommand({"show debug-file-directory", CB(handleDebugInfoLocation)}); @@ -3938,6 +3930,7 @@ void GdbEngine::setupEngine() showStatusMessage(tr("Setting up inferior...")); + const DebuggerRunParameters &rp = runParameters(); // Addint executable to modules list. Module module; module.startAddress = 0; @@ -4079,6 +4072,21 @@ void GdbEngine::reloadDebuggingHelpers() void GdbEngine::handleGdbDone() { + if (m_gdbProc.result() == ProcessResult::StartFailed) { + handleGdbStartFailed(); + QString msg; + const FilePath wd = m_gdbProc.workingDirectory(); + if (!wd.isReadableDir()) { + msg = failedToStartMessage() + ' ' + tr("The working directory \"%1\" is not usable.") + .arg(wd.toUserOutput()); + } else { + msg = RunWorker::userMessageForProcessError(QProcess::FailedToStart, + runParameters().debugger.command.executable()); + } + handleAdapterStartFailed(msg); + return; + } + const QProcess::ProcessError error = m_gdbProc.error(); if (error != QProcess::UnknownError) { QString msg = RunWorker::userMessageForProcessError(error, @@ -5004,7 +5012,7 @@ CoreInfo CoreInfo::readExecutableNameFromCore(const Runnable &debugger, const Fi proc.runBlocking(); if (proc.result() == ProcessResult::FinishedWithSuccess) { - QString output = proc.stdOut(); + QString output = proc.cleanedStdOut(); // Core was generated by `/data/dev/creator-2.6/bin/qtcreator'. // Program terminated with signal 11, Segmentation fault. int pos1 = output.indexOf("Core was generated by"); diff --git a/src/plugins/debugger/gdb/gdbengine.h b/src/plugins/debugger/gdb/gdbengine.h index a8dd2882e0d..49a090951a8 100644 --- a/src/plugins/debugger/gdb/gdbengine.h +++ b/src/plugins/debugger/gdb/gdbengine.h @@ -111,6 +111,7 @@ private: ////////// General Interface ////////// // The engine is still running just fine, but it failed to acquire a debuggee. void notifyInferiorSetupFailedHelper(const QString &msg); + void handleGdbStarted(); void handleGdbDone(); void readGdbStandardOutput(); void readGdbStandardError(); diff --git a/src/plugins/debugger/lldb/lldbengine.cpp b/src/plugins/debugger/lldb/lldbengine.cpp index f870ba78f40..5d54fc56b59 100644 --- a/src/plugins/debugger/lldb/lldbengine.cpp +++ b/src/plugins/debugger/lldb/lldbengine.cpp @@ -92,21 +92,15 @@ LldbEngine::LldbEngine() setDebuggerName("LLDB"); DebuggerSettings &ds = *debuggerSettings(); - connect(&ds.autoDerefPointers, &BaseAspect::changed, - this, &LldbEngine::updateLocals); + connect(&ds.autoDerefPointers, &BaseAspect::changed, this, &LldbEngine::updateLocals); connect(ds.createFullBacktrace.action(), &QAction::triggered, this, &LldbEngine::fetchFullBacktrace); - connect(&ds.useDebuggingHelpers, &BaseAspect::changed, - this, &LldbEngine::updateLocals); - connect(&ds.useDynamicType, &BaseAspect::changed, - this, &LldbEngine::updateLocals); - connect(&ds.intelFlavor, &BaseAspect::changed, - this, &LldbEngine::updateAll); + connect(&ds.useDebuggingHelpers, &BaseAspect::changed, this, &LldbEngine::updateLocals); + connect(&ds.useDynamicType, &BaseAspect::changed, this, &LldbEngine::updateLocals); + connect(&ds.intelFlavor, &BaseAspect::changed, this, &LldbEngine::updateAll); - connect(&m_lldbProc, &QtcProcess::errorOccurred, - this, &LldbEngine::handleLldbError); - connect(&m_lldbProc, &QtcProcess::finished, - this, &LldbEngine::handleLldbFinished); + connect(&m_lldbProc, &QtcProcess::started, this, &LldbEngine::handleLldbStarted); + connect(&m_lldbProc, &QtcProcess::done, this, &LldbEngine::handleLldbDone); connect(&m_lldbProc, &QtcProcess::readyReadStandardOutput, this, &LldbEngine::readLldbStandardOutput); connect(&m_lldbProc, &QtcProcess::readyReadStandardError, @@ -116,11 +110,6 @@ LldbEngine::LldbEngine() this, &LldbEngine::handleResponse, Qt::QueuedConnection); } -LldbEngine::~LldbEngine() -{ - m_lldbProc.disconnect(); -} - void LldbEngine::executeDebuggerCommand(const QString &command) { DebuggerCommand cmd("executeDebuggerCommand"); @@ -189,16 +178,13 @@ void LldbEngine::shutdownInferior() void LldbEngine::shutdownEngine() { QTC_ASSERT(state() == EngineShutdownRequested, qDebug() << state()); - if (m_lldbProc.isRunning()) - m_lldbProc.terminate(); - else - notifyEngineShutdownFinished(); + abortDebuggerProcess(); } void LldbEngine::abortDebuggerProcess() { if (m_lldbProc.isRunning()) - m_lldbProc.kill(); + m_lldbProc.stop(); else notifyEngineShutdownFinished(); } @@ -218,6 +204,22 @@ void LldbEngine::setupEngine() Environment environment = runParameters().debugger.environment; environment.appendOrSet("PYTHONUNBUFFERED", "1"); // avoid flushing problem on macOS DebuggerItem::addAndroidLldbPythonEnv(lldbCmd, environment); + + if (lldbCmd.osType() == OsTypeLinux) { + // LLDB 14 installation on Ubuntu 22.04 is broken: + // https://bugs.launchpad.net/ubuntu/+source/llvm-defaults/+bug/1972855 + // Brush over it: + QtcProcess lldbPythonPathFinder; + lldbPythonPathFinder.setCommand({lldbCmd, {"-P"}}); + lldbPythonPathFinder.start(); + lldbPythonPathFinder.waitForFinished(); + QString lldbPythonPath = lldbPythonPathFinder.cleanedStdOut(); + if (lldbPythonPath.endsWith('\n')) + lldbPythonPath.chop(1); + if (lldbPythonPath == "/usr/lib/local/lib/python3.10/dist-packages") + environment.appendOrSet("PYTHONPATH", "/usr/lib/llvm-14/lib/python3.10/dist-packages"); + } + m_lldbProc.setEnvironment(environment); if (runParameters().debugger.workingDirectory.isDir()) @@ -229,16 +231,10 @@ void LldbEngine::setupEngine() m_lldbProc.setCommand(CommandLine(lldbCmd)); m_lldbProc.start(); +} - if (!m_lldbProc.waitForStarted()) { - const QString msg = tr("Unable to start LLDB \"%1\": %2") - .arg(lldbCmd.toUserOutput(), m_lldbProc.errorString()); - notifyEngineSetupFailed(); - showMessage("ADAPTER START FAILED"); - if (!msg.isEmpty()) - ICore::showWarningWithOptions(adapterStartFailed(), msg); - return; - } +void LldbEngine::handleLldbStarted() +{ m_lldbProc.waitForReadyRead(1000); showStatusMessage(tr("Setting up inferior...")); @@ -282,6 +278,9 @@ void LldbEngine::setupEngine() "settings append target.source-map " + it.key() + ' ' + expand(it.value())); } + for (const QString &path : rp.solibSearchPath) + executeDebuggerCommand("settings append target.exec-search-paths " + path); + DebuggerCommand cmd2("setupInferior"); cmd2.arg("executable", rp.inferior.command.executable().toString()); cmd2.arg("breakonmain", rp.breakOnMain); @@ -785,12 +784,26 @@ void LldbEngine::doUpdateLocals(const UpdateParameters ¶ms) runCommand(cmd); } -void LldbEngine::handleLldbError(QProcess::ProcessError error) +void LldbEngine::handleLldbDone() { + if (m_lldbProc.result() == ProcessResult::StartFailed) { + notifyEngineSetupFailed(); + showMessage("ADAPTER START FAILED"); + ICore::showWarningWithOptions(adapterStartFailed(), tr("Unable to start LLDB \"%1\": %2") + .arg(runParameters().debugger.command.executable().toUserOutput(), + m_lldbProc.errorString())); + return; + } + + if (m_lldbProc.error() == QProcess::UnknownError) { + notifyDebuggerProcessFinished(m_lldbProc.resultData(), "LLDB"); + return; + } + + const QProcess::ProcessError error = m_lldbProc.error(); showMessage(QString("LLDB PROCESS ERROR: %1").arg(error)); switch (error) { case QProcess::Crashed: - m_lldbProc.disconnect(); notifyEngineShutdownFinished(); break; // will get a processExited() as well // impossible case QProcess::FailedToStart: @@ -799,7 +812,6 @@ void LldbEngine::handleLldbError(QProcess::ProcessError error) case QProcess::Timedout: default: //setState(EngineShutdownRequested, true); - m_lldbProc.kill(); AsynchronousMessageBox::critical(tr("LLDB I/O Error"), errorMessage(error)); break; } @@ -832,11 +844,6 @@ QString LldbEngine::errorMessage(QProcess::ProcessError error) const } } -void LldbEngine::handleLldbFinished() -{ - notifyDebuggerProcessFinished(m_lldbProc.resultData(), "LLDB"); -} - void LldbEngine::readLldbStandardError() { QString err = QString::fromUtf8(m_lldbProc.readAllStandardError()); @@ -924,7 +931,7 @@ void LldbEngine::handleStateNotification(const GdbMi &item) void LldbEngine::handleLocationNotification(const GdbMi &reportedLocation) { qulonglong address = reportedLocation["address"].toAddress(); - Utils::FilePath fileName = FilePath::fromUserInput(reportedLocation["file"].data()); + FilePath fileName = FilePath::fromUserInput(reportedLocation["file"].data()); QString function = reportedLocation["function"].data(); int lineNumber = reportedLocation["line"].toInt(); Location loc = Location(fileName, lineNumber); diff --git a/src/plugins/debugger/lldb/lldbengine.h b/src/plugins/debugger/lldb/lldbengine.h index 0e7e60bb713..5a0f7d63284 100644 --- a/src/plugins/debugger/lldb/lldbengine.h +++ b/src/plugins/debugger/lldb/lldbengine.h @@ -53,7 +53,6 @@ class LldbEngine : public CppDebuggerEngine public: LldbEngine(); - ~LldbEngine() override; signals: void outputReady(const QString &data); @@ -111,8 +110,8 @@ private: QString errorMessage(QProcess::ProcessError error) const; bool hasCapability(unsigned cap) const override; - void handleLldbFinished(); - void handleLldbError(QProcess::ProcessError error); + void handleLldbStarted(); + void handleLldbDone(); void readLldbStandardOutput(); void readLldbStandardError(); diff --git a/src/plugins/debugger/pdb/pdbengine.cpp b/src/plugins/debugger/pdb/pdbengine.cpp index bd34b36cddf..54375baf7f1 100644 --- a/src/plugins/debugger/pdb/pdbengine.cpp +++ b/src/plugins/debugger/pdb/pdbengine.cpp @@ -121,7 +121,8 @@ void PdbEngine::setupEngine() m_interpreter = runParameters().interpreter; QString bridge = ICore::resourcePath("debugger/pdbbridge.py").toString(); - connect(&m_proc, &QtcProcess::finished, this, &PdbEngine::handlePdbDone); + connect(&m_proc, &QtcProcess::started, this, &PdbEngine::handlePdbStarted); + connect(&m_proc, &QtcProcess::done, this, &PdbEngine::handlePdbDone); connect(&m_proc, &QtcProcess::readyReadStandardOutput, this, &PdbEngine::readPdbStandardOutput); connect(&m_proc, &QtcProcess::readyReadStandardError, this, &PdbEngine::readPdbStandardError); @@ -138,15 +139,10 @@ void PdbEngine::setupEngine() m_proc.setEnvironment(runParameters().debugger.environment); m_proc.setCommand(cmd); m_proc.start(); +} - if (!m_proc.waitForStarted()) { - notifyEngineSetupFailed(); - showMessage("ADAPTER START FAILED"); - ICore::showWarningWithOptions(tr("Adapter start failed"), m_proc.exitMessage()); - notifyEngineSetupFailed(); - return; - } - +void PdbEngine::handlePdbStarted() +{ notifyEngineSetupOk(); QTC_ASSERT(state() == EngineRunRequested, qDebug() << state()); @@ -416,6 +412,13 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const void PdbEngine::handlePdbDone() { + if (m_proc.result() == ProcessResult::StartFailed) { + notifyEngineSetupFailed(); + showMessage("ADAPTER START FAILED"); + ICore::showWarningWithOptions(tr("Adapter start failed"), m_proc.exitMessage()); + return; + } + const QProcess::ProcessError error = m_proc.error(); if (error != QProcess::UnknownError) { showMessage("HANDLE PDB ERROR"); diff --git a/src/plugins/debugger/pdb/pdbengine.h b/src/plugins/debugger/pdb/pdbengine.h index b8edaf5f44a..efde41e2ce9 100644 --- a/src/plugins/debugger/pdb/pdbengine.h +++ b/src/plugins/debugger/pdb/pdbengine.h @@ -100,6 +100,7 @@ private: QString errorMessage(QProcess::ProcessError error) const; bool hasCapability(unsigned cap) const override; + void handlePdbStarted(); void handlePdbDone(); void readPdbStandardOutput(); void readPdbStandardError(); diff --git a/src/plugins/debugger/qml/qmlengine.cpp b/src/plugins/debugger/qml/qmlengine.cpp index ef6a753b23f..c1511dbac7a 100644 --- a/src/plugins/debugger/qml/qmlengine.cpp +++ b/src/plugins/debugger/qml/qmlengine.cpp @@ -281,7 +281,7 @@ QmlEngine::QmlEngine() showMessage(QString::fromUtf8(d->process.readAllStandardError()), AppOutput); }); - connect(&d->process, &QtcProcess::finished, this, &QmlEngine::disconnected); + connect(&d->process, &QtcProcess::done, this, &QmlEngine::disconnected); connect(&d->process, &QtcProcess::started, this, &QmlEngine::handleLauncherStarted); debuggerConsole()->populateFileFinder(); diff --git a/src/plugins/debugger/stackhandler.cpp b/src/plugins/debugger/stackhandler.cpp index c42c196b09f..4001b854486 100644 --- a/src/plugins/debugger/stackhandler.cpp +++ b/src/plugins/debugger/stackhandler.cpp @@ -40,9 +40,8 @@ #include #include #include +#include -#include -#include #include #include #include @@ -410,14 +409,6 @@ static QString selectedText(QWidget *widget, bool useAll) return str; } -static void copyTextToClipboard(const QString &str) -{ - QClipboard *clipboard = QApplication::clipboard(); - if (clipboard->supportsSelection()) - clipboard->setText(str, QClipboard::Selection); - clipboard->setText(str, QClipboard::Clipboard); -} - // Write stack frames as task file for displaying it in the build issues pane. void StackHandler::saveTaskFile() { @@ -458,11 +449,11 @@ bool StackHandler::contextMenuEvent(const ItemViewEvent &ev) menu->addAction(debuggerSettings()->expandStack.action()); addAction(this, menu, tr("Copy Contents to Clipboard"), true, [ev] { - copyTextToClipboard(selectedText(ev.view(), true)); + setClipboardAndSelection(selectedText(ev.view(), true)); }); addAction(this, menu, tr("Copy Selection to Clipboard"), true, [ev] { - copyTextToClipboard(selectedText(ev.view(), false)); + setClipboardAndSelection(selectedText(ev.view(), false)); }); addAction(this, menu, tr("Save as Task File..."), true, [this] { saveTaskFile(); }); diff --git a/src/plugins/debugger/watchhandler.cpp b/src/plugins/debugger/watchhandler.cpp index b4656da8f2e..3663daa5296 100644 --- a/src/plugins/debugger/watchhandler.cpp +++ b/src/plugins/debugger/watchhandler.cpp @@ -60,7 +60,6 @@ #include #include -#include #include #include #include @@ -1663,14 +1662,6 @@ static QString removeWatchActionText(QString exp) return WatchModel::tr("Remove Expression Evaluator for \"%1\"").arg(Utils::quoteAmpersands(exp)); } -static void copyToClipboard(const QString &clipboardText) -{ - QClipboard *clipboard = QApplication::clipboard(); - if (clipboard->supportsSelection()) - clipboard->setText(clipboardText, QClipboard::Selection); - clipboard->setText(clipboardText, QClipboard::Clipboard); -} - void WatchModel::inputNewExpression() { QDialog dlg; @@ -1788,19 +1779,19 @@ bool WatchModel::contextMenuEvent(const ItemViewEvent &ev) addAction(this, menu, tr("Copy View Contents to Clipboard"), true, - [this] { copyToClipboard(editorContents()); }); + [this] { setClipboardAndSelection(editorContents()); }); addAction(this, menu, tr("Copy Current Value to Clipboard"), item, [this, name = item ? item->iname : QString()] { if (auto item = findItem(name)) - copyToClipboard(item->value); + setClipboardAndSelection(item->value); }); // addAction(menu, tr("Copy Selected Rows to Clipboard"), // selectionModel()->hasSelection(), - // [this] { copyToClipboard(editorContents(selectionModel()->selectedRows())); }); + // [this] { setClipboardAndSelection(editorContents(selectionModel()->selectedRows())); }); addAction(this, menu, tr("Open View Contents in Editor"), m_engine->debuggerActionsEnabled(), diff --git a/src/plugins/designer/CMakeLists.txt b/src/plugins/designer/CMakeLists.txt index 32fa078e9fc..ebc81260d0c 100644 --- a/src/plugins/designer/CMakeLists.txt +++ b/src/plugins/designer/CMakeLists.txt @@ -10,7 +10,7 @@ add_qtc_plugin(Designer codemodelhelpers.cpp codemodelhelpers.h cpp/formclasswizard.cpp cpp/formclasswizard.h cpp/formclasswizarddialog.cpp cpp/formclasswizarddialog.h - cpp/formclasswizardpage.cpp cpp/formclasswizardpage.h cpp/formclasswizardpage.ui + cpp/formclasswizardpage.cpp cpp/formclasswizardpage.h cpp/formclasswizardparameters.cpp cpp/formclasswizardparameters.h cpp/newclasswidget.cpp cpp/newclasswidget.h cpp/newclasswidget.ui designer_export.h diff --git a/src/plugins/designer/cpp/formclasswizardpage.cpp b/src/plugins/designer/cpp/formclasswizardpage.cpp index 52bdfe7ccba..81220b532cf 100644 --- a/src/plugins/designer/cpp/formclasswizardpage.cpp +++ b/src/plugins/designer/cpp/formclasswizardpage.cpp @@ -24,41 +24,53 @@ ****************************************************************************/ #include "formclasswizardpage.h" -#include "ui_formclasswizardpage.h" -#include "formclasswizardparameters.h" -#include +#include "formclasswizardparameters.h" +#include "newclasswidget.h" #include -#include -#include -#include +#include + +#include +#include + +#include +#include #include +#include +#include namespace Designer { namespace Internal { -// ----------------- FormClassWizardPage - -FormClassWizardPage::FormClassWizardPage(QWidget * parent) : - QWizardPage(parent), - m_ui(new Ui::FormClassWizardPage) +FormClassWizardPage::FormClassWizardPage() { - m_ui->setupUi(this); + setTitle(tr("Choose a Class Name")); - connect(m_ui->newClassWidget, &NewClassWidget::validChanged, this, - &FormClassWizardPage::slotValidChanged); + auto classGroupBox = new QGroupBox(this); + classGroupBox->setTitle(tr("Class")); - initFileGenerationSettings(); + m_newClassWidget = new NewClassWidget(classGroupBox); + m_newClassWidget->setHeaderExtension( + Utils::mimeTypeForName(CppEditor::Constants::CPP_HEADER_MIMETYPE).preferredSuffix()); + m_newClassWidget->setSourceExtension( + Utils::mimeTypeForName(CppEditor::Constants::CPP_SOURCE_MIMETYPE).preferredSuffix()); + m_newClassWidget->setLowerCaseFiles(lowercaseHeaderFiles()); + + connect(m_newClassWidget, &NewClassWidget::validChanged, + this, &FormClassWizardPage::slotValidChanged); setProperty(Utils::SHORT_TITLE_PROPERTY, tr("Class Details")); + + auto verticalLayout = new QVBoxLayout(classGroupBox); + verticalLayout->addWidget(m_newClassWidget); + + auto gridLayout = new QGridLayout(this); + gridLayout->addWidget(classGroupBox, 0, 0, 1, 1); } -FormClassWizardPage::~FormClassWizardPage() -{ - delete m_ui; -} +FormClassWizardPage::~FormClassWizardPage() = default; // Retrieve settings of CppEditor plugin. bool FormClassWizardPage::lowercaseHeaderFiles() @@ -70,45 +82,35 @@ bool FormClassWizardPage::lowercaseHeaderFiles() return Core::ICore::settings()->value(lowerCaseSettingsKey, QVariant(lowerCaseDefault)).toBool(); } -// Set up new class widget from settings -void FormClassWizardPage::initFileGenerationSettings() -{ - m_ui->newClassWidget->setHeaderExtension( - Utils::mimeTypeForName(CppEditor::Constants::CPP_HEADER_MIMETYPE).preferredSuffix()); - m_ui->newClassWidget->setSourceExtension( - Utils::mimeTypeForName(CppEditor::Constants::CPP_SOURCE_MIMETYPE).preferredSuffix()); - m_ui->newClassWidget->setLowerCaseFiles(lowercaseHeaderFiles()); -} - void FormClassWizardPage::setClassName(const QString &suggestedClassName) { // Is it valid, now? - m_ui->newClassWidget->setClassName(suggestedClassName); + m_newClassWidget->setClassName(suggestedClassName); slotValidChanged(); } Utils::FilePath FormClassWizardPage::filePath() const { - return m_ui->newClassWidget->filePath(); + return m_newClassWidget->filePath(); } void FormClassWizardPage::setFilePath(const Utils::FilePath &p) { - m_ui->newClassWidget->setFilePath(p); + m_newClassWidget->setFilePath(p); } void FormClassWizardPage::getParameters(FormClassWizardParameters *p) const { - p->className = m_ui->newClassWidget->className(); + p->className = m_newClassWidget->className(); p->path = filePath(); - p->sourceFile = m_ui->newClassWidget->sourceFileName(); - p->headerFile = m_ui->newClassWidget->headerFileName(); - p->uiFile = m_ui->newClassWidget-> formFileName(); + p->sourceFile = m_newClassWidget->sourceFileName(); + p->headerFile = m_newClassWidget->headerFileName(); + p->uiFile = m_newClassWidget-> formFileName(); } void FormClassWizardPage::slotValidChanged() { - const bool validNow = m_ui->newClassWidget->isValid(); + const bool validNow = m_newClassWidget->isValid(); if (m_isValid != validNow) { m_isValid = validNow; emit completeChanged(); @@ -123,7 +125,7 @@ bool FormClassWizardPage::isComplete() const bool FormClassWizardPage::validatePage() { QString errorMessage; - const bool rc = m_ui->newClassWidget->isValid(&errorMessage); + const bool rc = m_newClassWidget->isValid(&errorMessage); if (!rc) QMessageBox::warning(this, tr("%1 - Error").arg(title()), errorMessage); return rc; diff --git a/src/plugins/designer/cpp/formclasswizardpage.h b/src/plugins/designer/cpp/formclasswizardpage.h index 60e848433e1..7ba67ed42c6 100644 --- a/src/plugins/designer/cpp/formclasswizardpage.h +++ b/src/plugins/designer/cpp/formclasswizardpage.h @@ -25,6 +25,7 @@ #pragma once +#include #include namespace Utils { class FilePath; } @@ -36,21 +37,21 @@ class FormClassWizardGenerationParameters; namespace Internal { -namespace Ui { class FormClassWizardPage; } - +class NewClassWidget; class FormClassWizardPage : public QWizardPage { - Q_OBJECT + Q_DECLARE_TR_FUNCTIONS(Designer::Internal::FormClassWizardPage) public: - explicit FormClassWizardPage(QWidget *parent = nullptr); + FormClassWizardPage(); ~FormClassWizardPage() override; bool isComplete () const override; bool validatePage() override; void setClassName(const QString &suggestedClassName); + void setFilePath(const Utils::FilePath &); Utils::FilePath filePath() const; @@ -65,11 +66,8 @@ public: private: void slotValidChanged(); -private: - void initFileGenerationSettings(); - - Ui::FormClassWizardPage *m_ui = nullptr; bool m_isValid = false; + Designer::Internal::NewClassWidget *m_newClassWidget; }; } // namespace Internal diff --git a/src/plugins/designer/cpp/formclasswizardpage.ui b/src/plugins/designer/cpp/formclasswizardpage.ui deleted file mode 100644 index b58e58c4b5a..00000000000 --- a/src/plugins/designer/cpp/formclasswizardpage.ui +++ /dev/null @@ -1,33 +0,0 @@ - - - Designer::Internal::FormClassWizardPage - - - Choose a Class Name - - - - - - Class - - - - - - - - - - - - - Designer::Internal::NewClassWidget - QWidget -
designer/cpp/newclasswidget.h
- 1 -
-
- - -
diff --git a/src/plugins/designer/designer.qbs b/src/plugins/designer/designer.qbs index 739b1c1f989..ff98dfb04ff 100644 --- a/src/plugins/designer/designer.qbs +++ b/src/plugins/designer/designer.qbs @@ -70,7 +70,7 @@ QtcPlugin { files: [ "formclasswizard.cpp", "formclasswizard.h", "formclasswizarddialog.cpp", "formclasswizarddialog.h", - "formclasswizardpage.cpp", "formclasswizardpage.h", "formclasswizardpage.ui", + "formclasswizardpage.cpp", "formclasswizardpage.h", "formclasswizardparameters.cpp", "formclasswizardparameters.h", "newclasswidget.cpp", "newclasswidget.h", "newclasswidget.ui", ] diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index ca6d87e36fb..04f1a1ab043 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -444,14 +444,17 @@ void DockerDevicePrivate::startContainer() if (createProcess.result() != ProcessResult::FinishedWithSuccess) return; - m_container = createProcess.stdOut().trimmed(); + m_container = createProcess.cleanedStdOut().trimmed(); if (m_container.isEmpty()) return; LOG("Container via process: " << m_container); m_shell = std::make_unique(m_container); - connect(m_shell.get(), &DeviceShell::errorOccurred, this, [this] (QProcess::ProcessError error) { - qCWarning(dockerDeviceLog) << "Container shell encountered error:" << error; + connect(m_shell.get(), &DeviceShell::done, this, [this] (const ProcessResultData &resultData) { + if (resultData.m_error != QProcess::UnknownError) + return; + + qCWarning(dockerDeviceLog) << "Container shell encountered error:" << resultData.m_error; m_shell.reset(); DockerApi::recheckDockerDaemon(); @@ -988,11 +991,11 @@ void DockerDevicePrivate::fetchSystemEnviroment() proc.setCommand(q->withDockerExecCmd({"env", {}})); proc.start(); proc.waitForFinished(); - const QString remoteOutput = proc.stdOut(); + const QString remoteOutput = proc.cleanedStdOut(); m_cachedEnviroment = Environment(remoteOutput.split('\n', Qt::SkipEmptyParts), q->osType()); - const QString remoteError = proc.stdErr(); + const QString remoteError = proc.cleanedStdErr(); if (!remoteError.isEmpty()) qWarning("Cannot read container environment: %s\n", qPrintable(remoteError)); } @@ -1126,7 +1129,7 @@ public: }); connect(m_process, &Utils::QtcProcess::readyReadStandardError, this, [this] { - const QString out = DockerDevice::tr("Error: %1").arg(m_process->stdErr()); + const QString out = DockerDevice::tr("Error: %1").arg(m_process->cleanedStdErr()); m_log->append(DockerDevice::tr("Error: %1").arg(out)); }); diff --git a/src/plugins/docker/dockersettings.cpp b/src/plugins/docker/dockersettings.cpp index fc28988e3ed..f9c615ed0ea 100644 --- a/src/plugins/docker/dockersettings.cpp +++ b/src/plugins/docker/dockersettings.cpp @@ -82,14 +82,9 @@ void DockerSettings::updateImageList() { QtcProcess process; process.setCommand({"docker", {"search", imageListFilter.value()}}); - - connect(&process, &QtcProcess::finished, this, [&process, this] { - const QString data = QString::fromUtf8(process.readAllStandardOutput()); - imageList.setValue(data); - }); - process.start(); process.waitForFinished(); + imageList.setValue(process.cleanedStdOut()); } void DockerSettings::readSettings(const QSettings *settings) diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index 79e8153c01b..812bb994d0a 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -864,15 +864,6 @@ static QByteArray toLocalEncoding(const QString &text) #endif } -static QString fromLocalEncoding(const QByteArray &data) -{ -#if defined(Q_OS_WIN) - return QString::fromLocal8Bit(data).replace("\n", "\r\n"); -#else - return QString::fromLocal8Bit(data); -#endif -} - static QString getProcessOutput(const QString &command, const QString &input) { Utils::QtcProcess proc; @@ -884,7 +875,7 @@ static QString getProcessOutput(const QString &command, const QString &input) // Solution is to create a QObject for each process and emit finished state. proc.waitForFinished(); - return fromLocalEncoding(proc.readAllStandardOutput()); + return proc.cleanedStdOut(); } static const QMap &vimKeyNames() @@ -1246,7 +1237,7 @@ public: return '\n'; if (m_key == Key_Escape) return QChar(27); - return QChar(m_xkey); + return QChar(m_xkey & 0xffff); // FIXME } QString toString() const @@ -1263,7 +1254,7 @@ public: else if (m_xkey == '>') key = ""; else - key = QChar(m_xkey); + key = QChar(m_xkey & 0xffff); // FIXME } bool shift = isShift(); diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp index a32047d7f87..5dd3e199b91 100644 --- a/src/plugins/git/changeselectiondialog.cpp +++ b/src/plugins/git/changeselectiondialog.cpp @@ -162,9 +162,11 @@ void ChangeSelectionDialog::setDetails() QPalette palette; if (m_process->result() == ProcessResult::FinishedWithSuccess) { - m_ui->detailsText->setPlainText(m_process->stdOut()); + m_ui->detailsText->setPlainText(m_process->cleanedStdOut()); palette.setColor(QPalette::Text, theme->color(Theme::TextColorNormal)); m_ui->changeNumberEdit->setPalette(palette); + } else if (m_process->result() == ProcessResult::StartFailed) { + m_ui->detailsText->setPlainText(tr("Error: Could not start Git.")); } else { m_ui->detailsText->setPlainText(tr("Error: Unknown reference")); palette.setColor(QPalette::Text, theme->color(Theme::TextColorError)); @@ -218,17 +220,12 @@ void ChangeSelectionDialog::recalculateDetails() } m_process.reset(new QtcProcess); + connect(m_process.get(), &QtcProcess::done, this, &ChangeSelectionDialog::setDetails); m_process->setWorkingDirectory(workingDir); m_process->setEnvironment(m_gitEnvironment); m_process->setCommand({m_gitExecutable, {"show", "--decorate", "--stat=80", ref}}); - - connect(m_process.get(), &QtcProcess::finished, this, &ChangeSelectionDialog::setDetails); - m_process->start(); - if (!m_process->waitForStarted()) - m_ui->detailsText->setPlainText(tr("Error: Could not start Git.")); - else - m_ui->detailsText->setPlainText(tr("Fetching commit data...")); + m_ui->detailsText->setPlainText(tr("Fetching commit data...")); } void ChangeSelectionDialog::changeTextChanged(const QString &text) diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp index 9c835c98a5b..c213744b61a 100644 --- a/src/plugins/git/gerrit/gerritmodel.cpp +++ b/src/plugins/git/gerrit/gerritmodel.cpp @@ -375,7 +375,7 @@ void QueryContext::timeout() arg(timeOutMS / 1000), QMessageBox::NoButton, parent); QPushButton *terminateButton = box.addButton(tr("Terminate"), QMessageBox::YesRole); box.addButton(tr("Keep Running"), QMessageBox::NoRole); - connect(&m_process, &QtcProcess::finished, &box, &QDialog::reject); + connect(&m_process, &QtcProcess::done, &box, &QDialog::reject); box.exec(); if (m_process.state() != QProcess::Running) return; diff --git a/src/plugins/git/gerrit/gerritserver.cpp b/src/plugins/git/gerrit/gerritserver.cpp index 4ddbcfd1363..7fc9ae4c7ef 100644 --- a/src/plugins/git/gerrit/gerritserver.cpp +++ b/src/plugins/git/gerrit/gerritserver.cpp @@ -247,7 +247,7 @@ int GerritServer::testConnection() client->vcsFullySynchronousExec(proc, {}, {curlBinary, arguments}, Core::ShellCommand::NoOutput); if (proc.result() == ProcessResult::FinishedWithSuccess) { - QString output = proc.stdOut(); + QString output = proc.cleanedStdOut(); // Gerrit returns an empty response for /p/qt-creator/a/accounts/self // so consider this as 404. if (output.isEmpty()) @@ -266,7 +266,7 @@ int GerritServer::testConnection() if (proc.exitCode() == CertificateError) return CertificateError; const QRegularExpression errorRegexp("returned error: (\\d+)"); - QRegularExpressionMatch match = errorRegexp.match(proc.stdErr()); + QRegularExpressionMatch match = errorRegexp.match(proc.cleanedStdErr()); if (match.hasMatch()) return match.captured(1).toInt(); return UnknownError; @@ -346,7 +346,7 @@ bool GerritServer::resolveVersion(const GerritParameters &p, bool forceReload) arguments << p.portFlag << QString::number(port); arguments << hostArgument() << "gerrit" << "version"; client->vcsFullySynchronousExec(proc, {}, {p.ssh, arguments}, Core::ShellCommand::NoOutput); - QString stdOut = proc.stdOut().trimmed(); + QString stdOut = proc.cleanedStdOut().trimmed(); stdOut.remove("gerrit version "); version = stdOut; if (version.isEmpty()) @@ -359,7 +359,7 @@ bool GerritServer::resolveVersion(const GerritParameters &p, bool forceReload) // REST endpoint for version is only available from 2.8 and up. Do not consider invalid // if it fails. if (proc.result() == ProcessResult::FinishedWithSuccess) { - QString output = proc.stdOut(); + QString output = proc.cleanedStdOut(); if (output.isEmpty()) return false; output.remove(0, output.indexOf('\n')); // Strip first line diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 4d42372c72b..1a2b211156b 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -761,8 +761,8 @@ public: // No conflicts => do nothing if (proc.result() == ProcessResult::FinishedWithSuccess) return; - handler.readStdOut(proc.stdOut()); - handler.readStdErr(proc.stdErr()); + handler.readStdOut(proc.cleanedStdOut()); + handler.readStdErr(proc.cleanedStdErr()); } private: @@ -944,7 +944,7 @@ FilePaths GitClient::unmanagedFiles(const FilePaths &filePaths) const if (proc.result() != ProcessResult::FinishedWithSuccess) return filePaths; const QStringList managedFilePaths - = transform(proc.stdOut().split('\0', Qt::SkipEmptyParts), + = transform(proc.cleanedStdOut().split('\0', Qt::SkipEmptyParts), [&wd](const QString &fp) { return wd.absoluteFilePath(fp); }); const QStringList filtered = Utils::filtered(it.value(), [&managedFilePaths, &wd](const QString &fp) { return !managedFilePaths.contains(wd.absoluteFilePath(fp)); @@ -1141,8 +1141,7 @@ void GitClient::diffBranch(const FilePath &workingDirectory, const QString &bran void GitClient::merge(const FilePath &workingDirectory, const QStringList &unmergedFileNames) { auto mergeTool = new MergeTool(this); - if (!mergeTool->start(workingDirectory, unmergedFileNames)) - delete mergeTool; + mergeTool->start(workingDirectory, unmergedFileNames); } void GitClient::status(const FilePath &workingDirectory) const @@ -1515,7 +1514,7 @@ void GitClient::recoverDeletedFiles(const FilePath &workingDirectory) vcsFullySynchronousExec(proc, workingDirectory, {"ls-files", "--deleted"}, VcsCommand::SuppressCommandLogging); if (proc.result() == ProcessResult::FinishedWithSuccess) { - const QString stdOut = proc.stdOut().trimmed(); + const QString stdOut = proc.cleanedStdOut().trimmed(); if (stdOut.isEmpty()) { VcsOutputWindow::appendError(tr("Nothing to recover")); return; @@ -1542,11 +1541,11 @@ bool GitClient::synchronousLog(const FilePath &workingDirectory, const QStringLi vcsFullySynchronousExec(proc, workingDirectory, allArguments, flags, vcsTimeoutS(), encoding(workingDirectory, "i18n.logOutputEncoding")); if (proc.result() == ProcessResult::FinishedWithSuccess) { - *output = proc.stdOut(); + *output = proc.cleanedStdOut(); return true; } else { msgCannotRun(tr("Cannot obtain log of \"%1\": %2") - .arg(workingDirectory.toUserOutput(), proc.stdErr()), errorMessageIn); + .arg(workingDirectory.toUserOutput(), proc.cleanedStdErr()), errorMessageIn); return false; } } @@ -1596,7 +1595,7 @@ bool GitClient::synchronousReset(const FilePath &workingDirectory, QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments); - const QString stdOut = proc.stdOut(); + const QString stdOut = proc.cleanedStdOut(); VcsOutputWindow::append(stdOut); // Note that git exits with 1 even if the operation is successful // Assume real failure if the output does not contain "foo.cpp modified" @@ -1604,10 +1603,10 @@ bool GitClient::synchronousReset(const FilePath &workingDirectory, if (proc.result() != ProcessResult::FinishedWithSuccess && (!stdOut.contains("modified") && !stdOut.contains("Unstaged changes after reset"))) { if (files.isEmpty()) { - msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(arguments, workingDirectory, proc.cleanedStdErr(), errorMessage); } else { msgCannotRun(tr("Cannot reset %n files in \"%1\": %2", nullptr, files.size()) - .arg(workingDirectory.toUserOutput(), proc.stdErr()), + .arg(workingDirectory.toUserOutput(), proc.cleanedStdErr()), errorMessage); } return false; @@ -1621,7 +1620,7 @@ bool GitClient::synchronousInit(const FilePath &workingDirectory) QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, QStringList{"init"}); // '[Re]Initialized...' - VcsOutputWindow::append(proc.stdOut()); + VcsOutputWindow::append(proc.cleanedStdOut()); if (proc.result() == ProcessResult::FinishedWithSuccess) { resetCachedVcsInfo(workingDirectory); return true; @@ -1653,7 +1652,7 @@ bool GitClient::synchronousCheckoutFiles(const FilePath &workingDirectory, QStri //: Meaning of the arguments: %1: revision, %2: files, %3: repository, //: %4: Error message msgCannotRun(tr("Cannot checkout \"%1\" of %2 in \"%3\": %4") - .arg(revision, fileArg, workingDirectory.toUserOutput(), proc.stdErr()), + .arg(revision, fileArg, workingDirectory.toUserOutput(), proc.cleanedStdErr()), errorMessage); return false; } @@ -1701,10 +1700,10 @@ bool GitClient::synchronousRevListCmd(const FilePath &workingDirectory, const QS QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(arguments, workingDirectory, proc.cleanedStdErr(), errorMessage); return false; } - *output = proc.stdOut(); + *output = proc.cleanedStdOut(); return true; } @@ -1765,7 +1764,7 @@ QString GitClient::synchronousCurrentLocalBranch(const FilePath &workingDirector QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, {"symbolic-ref", HEAD}, silentFlags); if (proc.result() == ProcessResult::FinishedWithSuccess) { - branch = proc.stdOut().trimmed(); + branch = proc.cleanedStdOut().trimmed(); } else { const QString gitDir = findGitDirForRepository(workingDirectory); const QString rebaseHead = gitDir + "/rebase-merge/head-name"; @@ -1790,11 +1789,11 @@ bool GitClient::synchronousHeadRefs(const FilePath &workingDirectory, QStringLis QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(arguments, workingDirectory, proc.cleanedStdErr(), errorMessage); return false; } - const QString stdOut = proc.stdOut(); + const QString stdOut = proc.cleanedStdOut(); const QString headSha = stdOut.left(10); QString rest = stdOut.mid(15); @@ -1839,7 +1838,7 @@ QString GitClient::synchronousTopic(const FilePath &workingDirectory) const QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, QStringList{"describe"}, VcsCommand::NoOutput); if (proc.result() == ProcessResult::FinishedWithSuccess) { - const QString stdOut = proc.stdOut().trimmed(); + const QString stdOut = proc.cleanedStdOut().trimmed(); if (!stdOut.isEmpty()) return stdOut; } @@ -1852,9 +1851,9 @@ bool GitClient::synchronousRevParseCmd(const FilePath &workingDirectory, const Q const QStringList arguments = {"rev-parse", ref}; QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags); - *output = proc.stdOut().trimmed(); + *output = proc.cleanedStdOut().trimmed(); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(arguments, workingDirectory, proc.cleanedStdErr(), errorMessage); return false; } @@ -1869,7 +1868,7 @@ QString GitClient::synchronousTopRevision(const FilePath &workingDirectory, QDat vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags); if (proc.result() != ProcessResult::FinishedWithSuccess) return QString(); - const QStringList output = proc.stdOut().trimmed().split(':'); + const QStringList output = proc.cleanedStdOut().trimmed().split(':'); if (dateTime && output.size() > 1) { bool ok = false; const qint64 timeT = output.at(1).toLongLong(&ok); @@ -1889,7 +1888,7 @@ bool GitClient::isFastForwardMerge(const FilePath &workingDirectory, const QStri { QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, {"merge-base", HEAD, branch}, silentFlags); - return proc.stdOut().trimmed() == synchronousTopRevision(workingDirectory); + return proc.cleanedStdOut().trimmed() == synchronousTopRevision(workingDirectory); } // Format an entry in a one-liner for selection list using git log. @@ -1902,10 +1901,10 @@ QString GitClient::synchronousShortDescription(const FilePath &workingDirectory, vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags); if (proc.result() != ProcessResult::FinishedWithSuccess) { VcsOutputWindow::appendSilently(tr("Cannot describe revision \"%1\" in \"%2\": %3") - .arg(revision, workingDirectory.toUserOutput(), proc.stdErr())); + .arg(revision, workingDirectory.toUserOutput(), proc.cleanedStdErr())); return revision; } - return stripLastNewline(proc.stdOut()); + return stripLastNewline(proc.cleanedStdOut()); } // Create a default message to be used for describing stashes @@ -1982,7 +1981,7 @@ bool GitClient::executeSynchronousStash(const FilePath &workingDirectory, QtcProcess proc; vcsSynchronousExec(proc, workingDirectory, arguments, flags); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(arguments, workingDirectory, proc.cleanedStdErr(), errorMessage); return false; } @@ -2021,9 +2020,9 @@ bool GitClient::synchronousBranchCmd(const FilePath &workingDirectory, QStringLi branchArgs.push_front("branch"); QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, branchArgs); - *output = proc.stdOut(); + *output = proc.cleanedStdOut(); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(branchArgs, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(branchArgs, workingDirectory, proc.cleanedStdErr(), errorMessage); return false; } return true; @@ -2035,9 +2034,9 @@ bool GitClient::synchronousTagCmd(const FilePath &workingDirectory, QStringList tagArgs.push_front("tag"); QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, tagArgs); - *output = proc.stdOut(); + *output = proc.cleanedStdOut(); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(tagArgs, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(tagArgs, workingDirectory, proc.cleanedStdErr(), errorMessage); return false; } return true; @@ -2049,9 +2048,9 @@ bool GitClient::synchronousForEachRefCmd(const FilePath &workingDirectory, QStri args.push_front("for-each-ref"); QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, args, silentFlags); - *output = proc.stdOut(); + *output = proc.cleanedStdOut(); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(args, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(args, workingDirectory, proc.cleanedStdErr(), errorMessage); return false; } return true; @@ -2070,9 +2069,9 @@ bool GitClient::synchronousRemoteCmd(const FilePath &workingDirectory, QStringLi QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, remoteArgs, silent ? silentFlags : 0); - const QString stdErr = proc.stdErr(); + const QString stdErr = proc.cleanedStdErr(); *errorMessage = stdErr; - *output = proc.stdOut(); + *output = proc.cleanedStdOut(); if (proc.result() != ProcessResult::FinishedWithSuccess) { msgCannotRun(remoteArgs, workingDirectory, stdErr, errorMessage); @@ -2116,10 +2115,10 @@ QStringList GitClient::synchronousSubmoduleStatus(const FilePath &workingDirecto if (proc.result() != ProcessResult::FinishedWithSuccess) { msgCannotRun(tr("Cannot retrieve submodule status of \"%1\": %2") - .arg(workingDirectory.toUserOutput(), proc.stdErr()), errorMessage); + .arg(workingDirectory.toUserOutput(), proc.cleanedStdErr()), errorMessage); return QStringList(); } - return splitLines(proc.stdOut()); + return splitLines(proc.cleanedStdOut()); } SubmoduleDataMap GitClient::submoduleList(const FilePath &workingDirectory) const @@ -2195,7 +2194,7 @@ QByteArray GitClient::synchronousShow(const FilePath &workingDirectory, const QS QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments, flags); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(arguments, workingDirectory, proc.stdErr(), nullptr); + msgCannotRun(arguments, workingDirectory, proc.cleanedStdErr(), nullptr); return {}; } return proc.rawStdOut(); @@ -2211,7 +2210,7 @@ bool GitClient::cleanList(const FilePath &workingDirectory, const QString &modul QtcProcess proc; vcsFullySynchronousExec(proc, directory, arguments, VcsCommand::ForceCLocale); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(arguments, directory, proc.stdErr(), errorMessage); + msgCannotRun(arguments, directory, proc.cleanedStdErr(), errorMessage); return false; } @@ -2219,7 +2218,7 @@ bool GitClient::cleanList(const FilePath &workingDirectory, const QString &modul const QString relativeBase = modulePath.isEmpty() ? QString() : modulePath + '/'; const QString prefix = "Would remove "; const QStringList removeLines = Utils::filtered( - splitLines(proc.stdOut()), [](const QString &s) { + splitLines(proc.cleanedStdOut()), [](const QString &s) { return s.startsWith("Would remove "); }); *files = Utils::transform(removeLines, [&relativeBase, &prefix](const QString &s) -> QString { @@ -2257,7 +2256,7 @@ bool GitClient::synchronousApplyPatch(const FilePath &workingDirectory, QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments); - const QString stdErr = proc.stdErr(); + const QString stdErr = proc.cleanedStdErr(); if (proc.result() == ProcessResult::FinishedWithSuccess) { if (!stdErr.isEmpty()) *errorMessage = tr("There were warnings while applying \"%1\" to \"%2\":\n%3") @@ -2394,7 +2393,7 @@ GitClient::StatusResult GitClient::gitStatus(const FilePath &workingDirectory, S QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags); - const QString stdOut = proc.stdOut(); + const QString stdOut = proc.cleanedStdOut(); if (output) *output = stdOut; @@ -2404,7 +2403,7 @@ GitClient::StatusResult GitClient::gitStatus(const FilePath &workingDirectory, S // Is it something really fatal? if (!statusRc && !branchKnown) { if (errorMessage) { - *errorMessage = tr("Cannot obtain status: %1").arg(proc.stdErr()); + *errorMessage = tr("Cannot obtain status: %1").arg(proc.cleanedStdErr()); } return StatusFailed; } @@ -2547,7 +2546,7 @@ QStringList GitClient::synchronousRepositoryBranches(const QString &repositoryUR // split "82bfad2f51d34e98b18982211c82220b8db049brefs/heads/master" bool headFound = false; bool branchFound = false; - const QStringList lines = proc.stdOut().split('\n'); + const QStringList lines = proc.cleanedStdOut().split('\n'); for (const QString &line : lines) { if (line.endsWith("\tHEAD")) { QTC_CHECK(headSha.isNull()); @@ -3179,7 +3178,7 @@ void GitClient::synchronousAbortCommand(const FilePath &workingDir, const QStrin QtcProcess proc; vcsFullySynchronousExec(proc, workingDir, {abortCommand, "--abort"}, VcsCommand::ExpectRepoChanges | VcsCommand::ShowSuccessMessage); - VcsOutputWindow::append(proc.stdOut()); + VcsOutputWindow::append(proc.cleanedStdOut()); } QString GitClient::synchronousTrackingBranch(const FilePath &workingDirectory, const QString &branch) @@ -3529,12 +3528,12 @@ bool GitClient::synchronousStashRemove(const FilePath &workingDirectory, const Q QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, arguments); if (proc.result() == ProcessResult::FinishedWithSuccess) { - const QString output = proc.stdOut(); + const QString output = proc.cleanedStdOut(); if (!output.isEmpty()) VcsOutputWindow::append(output); return true; } else { - msgCannotRun(arguments, workingDirectory, proc.stdErr(), errorMessage); + msgCannotRun(arguments, workingDirectory, proc.cleanedStdErr(), errorMessage); return false; } } @@ -3548,11 +3547,11 @@ bool GitClient::synchronousStashList(const FilePath &workingDirectory, QListpush_back(stash); @@ -3589,7 +3588,7 @@ QString GitClient::readOneLine(const FilePath &workingDirectory, const QStringLi vcsFullySynchronousExec(proc, workingDirectory, arguments, silentFlags, vcsTimeoutS(), codec); if (proc.result() != ProcessResult::FinishedWithSuccess) return QString(); - return proc.stdOut().trimmed(); + return proc.cleanedStdOut().trimmed(); } // determine version as '(major << 16) + (minor << 8) + patch' or 0. @@ -3615,13 +3614,13 @@ unsigned GitClient::synchronousGitVersion(QString *errorMessage) const QtcProcess proc; vcsSynchronousExec(proc, {}, {"--version"}, silentFlags); if (proc.result() != ProcessResult::FinishedWithSuccess) { - msgCannotRun(tr("Cannot determine Git version: %1").arg(proc.stdErr()), errorMessage); + msgCannotRun(tr("Cannot determine Git version: %1").arg(proc.cleanedStdErr()), errorMessage); return 0; } // cut 'git version 1.6.5.1.sha' // another form: 'git version 1.9.rc1' - const QString output = proc.stdOut(); + const QString output = proc.cleanedStdOut(); const QRegularExpression versionPattern("^[^\\d]+(\\d+)\\.(\\d+)\\.(\\d+|rc\\d).*$"); QTC_ASSERT(versionPattern.isValid(), return 0); const QRegularExpressionMatch match = versionPattern.match(output); diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index 8a265d35bc5..6ab4b8edc6b 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -141,11 +141,9 @@ FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const errorMessage->clear(); FilePath binPath = binaryPath.filePath(); - if (!binPath.isAbsolutePath()) { - Environment env = Environment::systemEnvironment(); - env.prependOrSetPath(path.filePath()); - binPath = env.searchInPath(binPath.toString()); - } + if (!binPath.isAbsolutePath()) + binPath = binPath.searchInPath({path.filePath()}, FilePath::PrependToPath); + if (binPath.isEmpty()) { if (ok) *ok = false; diff --git a/src/plugins/git/mergetool.cpp b/src/plugins/git/mergetool.cpp index 97259483beb..71ac736ef26 100644 --- a/src/plugins/git/mergetool.cpp +++ b/src/plugins/git/mergetool.cpp @@ -30,9 +30,7 @@ #include #include #include -#include #include -#include #include #include @@ -45,39 +43,26 @@ namespace Git { namespace Internal { MergeTool::MergeTool(QObject *parent) : QObject(parent) -{ } - -MergeTool::~MergeTool() { - delete m_process; -} - -bool MergeTool::start(const FilePath &workingDirectory, const QStringList &files) -{ - QStringList arguments; - arguments << "mergetool" << "-y" << files; + connect(&m_process, &QtcProcess::done, this, &MergeTool::done); + connect(&m_process, &QtcProcess::readyReadStandardOutput, this, &MergeTool::readData); Environment env = Environment::systemEnvironment(); env.set("LANG", "C"); env.set("LANGUAGE", "C"); - m_process = new QtcProcess; - m_process->setProcessMode(ProcessMode::Writer); - m_process->setWorkingDirectory(workingDirectory); - m_process->setEnvironment(env); - m_process->setProcessChannelMode(QProcess::MergedChannels); - const Utils::FilePath binary = GitClient::instance()->vcsBinary(); - const CommandLine cmd = {binary, arguments}; + m_process.setEnvironment(env); + m_process.setProcessMode(ProcessMode::Writer); + m_process.setProcessChannelMode(QProcess::MergedChannels); +} + +void MergeTool::start(const FilePath &workingDirectory, const QStringList &files) +{ + QStringList arguments; + arguments << "mergetool" << "-y" << files; + const CommandLine cmd = {GitClient::instance()->vcsBinary(), arguments}; VcsOutputWindow::appendCommand(workingDirectory, cmd); - m_process->setCommand(cmd); - m_process->start(); - if (m_process->waitForStarted()) { - connect(m_process, &QtcProcess::finished, this, &MergeTool::done); - connect(m_process, &QtcProcess::readyReadStandardOutput, this, &MergeTool::readData); - } else { - delete m_process; - m_process = nullptr; - return false; - } - return true; + m_process.setCommand(cmd); + m_process.setWorkingDirectory(workingDirectory); + m_process.start(); } MergeTool::FileState MergeTool::parseStatus(const QString &line, QString &extraInfo) @@ -148,8 +133,7 @@ QString MergeTool::stateName(MergeTool::FileState state, const QString &extraInf void MergeTool::chooseAction() { - m_merging = (m_mergeType == NormalMerge); - if (m_merging) + if (m_mergeType == NormalMerge) return; QMessageBox msgBox; msgBox.setWindowTitle(tr("Merge Conflict")); @@ -206,7 +190,7 @@ void MergeTool::prompt(const QString &title, const QString &question) void MergeTool::readData() { - QString newData = QString::fromLocal8Bit(m_process->readAllStandardOutput()); + QString newData = QString::fromLocal8Bit(m_process.readAllStandardOutput()); newData.remove('\r'); VcsOutputWindow::append(newData); QString data = m_unfinishedLine + newData; @@ -230,7 +214,7 @@ void MergeTool::readData() tr("Merge tool is not configured."), tr("Run git config --global merge.tool <tool> " "to configure it, then try again."))); - m_process->kill(); + m_process.stop(); } else { m_unfinishedLine = data; } @@ -254,22 +238,21 @@ void MergeTool::readLine(const QString &line) void MergeTool::done() { - const FilePath workingDirectory = m_process->workingDirectory(); - int exitCode = m_process->exitCode(); - if (!exitCode) { - VcsOutputWindow::appendMessage(tr("Merge tool process finished successfully.")); - } else { - VcsOutputWindow::appendError(tr("Merge tool process terminated with exit code %1") - .arg(exitCode)); - } - GitClient::instance()->continueCommandIfNeeded(workingDirectory, exitCode == 0); + const bool success = m_process.result() == ProcessResult::FinishedWithSuccess; + if (success) + VcsOutputWindow::appendMessage(m_process.exitMessage()); + else + VcsOutputWindow::appendError(m_process.exitMessage()); + + const FilePath workingDirectory = m_process.workingDirectory(); + GitClient::instance()->continueCommandIfNeeded(workingDirectory, success); GitPlugin::emitRepositoryChanged(workingDirectory); deleteLater(); } void MergeTool::write(const QString &str) { - m_process->write(str); + m_process.write(str); VcsOutputWindow::append(str); } diff --git a/src/plugins/git/mergetool.h b/src/plugins/git/mergetool.h index 7d0fba01b80..735c53ea711 100644 --- a/src/plugins/git/mergetool.h +++ b/src/plugins/git/mergetool.h @@ -25,6 +25,8 @@ #pragma once +#include + #include #include @@ -32,12 +34,6 @@ QT_BEGIN_NAMESPACE class QMessageBox; QT_END_NAMESPACE -namespace Utils -{ -class FilePath; -class QtcProcess; -} - namespace Git { namespace Internal { @@ -56,8 +52,7 @@ class MergeTool : public QObject public: explicit MergeTool(QObject *parent = nullptr); - ~MergeTool() override; - bool start(const Utils::FilePath &workingDirectory, const QStringList &files = {}); + void start(const Utils::FilePath &workingDirectory, const QStringList &files = {}); enum MergeType { NormalMerge, @@ -79,7 +74,7 @@ private: void chooseAction(); void addButton(QMessageBox *msgBox, const QString &text, char key); - Utils::QtcProcess *m_process = nullptr; + Utils::QtcProcess m_process; MergeType m_mergeType = NormalMerge; QString m_fileName; FileState m_localState = UnknownState; @@ -87,7 +82,6 @@ private: FileState m_remoteState = UnknownState; QString m_remoteInfo; QString m_unfinishedLine; - bool m_merging = false; }; } // namespace Internal diff --git a/src/plugins/gitlab/queryrunner.cpp b/src/plugins/gitlab/queryrunner.cpp index fe46db842e0..55d1572bd32 100644 --- a/src/plugins/gitlab/queryrunner.cpp +++ b/src/plugins/gitlab/queryrunner.cpp @@ -37,6 +37,8 @@ #include +using namespace Utils; + namespace GitLab { const char API_PREFIX[] = "/api/v4"; @@ -100,15 +102,13 @@ QString Query::toString() const return query; } -QueryRunner::QueryRunner(const Query &query, const Utils::Id &id, QObject *parent) +QueryRunner::QueryRunner(const Query &query, const Id &id, QObject *parent) : QObject(parent) - , m_serverId(id) { const GitLabParameters *p = GitLabPlugin::globalParameters(); - const auto server = p->serverForId(m_serverId); + const auto server = p->serverForId(id); QStringList args = server.curlArguments(); - m_paginated = query.hasPaginatedResults(); - if (m_paginated) + if (query.hasPaginatedResults()) args << "-i"; if (!server.token.isEmpty()) args << "--header" << "PRIVATE-TOKEN: " + server.token; @@ -118,69 +118,31 @@ QueryRunner::QueryRunner(const Query &query, const Utils::Id &id, QObject *paren url += query.toString(); args << url; m_process.setCommand({p->curl, args}); - connect(&m_process, &Utils::QtcProcess::finished, this, &QueryRunner::processFinished); - connect(&m_process, &Utils::QtcProcess::errorOccurred, this, &QueryRunner::processError); -} - -QueryRunner::~QueryRunner() -{ - m_process.disconnect(); - terminate(); -} - -void QueryRunner::start() -{ - QTC_ASSERT(!m_running, return); - m_running = true; - m_process.start(); -} - -void QueryRunner::terminate() -{ - m_process.stop(); - m_process.waitForFinished(); -} - -void QueryRunner::errorTermination(const QString &msg) -{ - if (!m_running) - return; - VcsBase::VcsOutputWindow::appendError(msg); - m_running = false; - emit finished(); -} - -void QueryRunner::processError(QProcess::ProcessError /*error*/) -{ - const QString msg = tr("Error running %1: %2") - .arg(m_process.commandLine().executable().toUserOutput(), - m_process.errorString()); - errorTermination(msg); -} -void QueryRunner::processFinished() -{ - const QString executable = m_process.commandLine().executable().toUserOutput(); - if (m_process.exitStatus() != QProcess::NormalExit) { - errorTermination(tr("%1 crashed.").arg(executable)); - return; - } else if (int exitCode = m_process.exitCode()) { - if (exitCode == 35 || exitCode == 60) { // common ssl certificate issues - if (GitLabPlugin::handleCertificateIssue(m_serverId)) { - m_running = false; + connect(&m_process, &QtcProcess::done, this, [this, id] { + if (m_process.result() != ProcessResult::FinishedWithSuccess) { + const int exitCode = m_process.exitCode(); + if (m_process.exitStatus() == QProcess::NormalExit + && (exitCode == 35 || exitCode == 60) // common ssl certificate issues + && GitLabPlugin::handleCertificateIssue(id)) { // prepend -k for re-requesting the same query - Utils::CommandLine cmdline = m_process.commandLine(); + CommandLine cmdline = m_process.commandLine(); cmdline.prependArgs({"-k"}); m_process.setCommand(cmdline); start(); return; } + VcsBase::VcsOutputWindow::appendError(m_process.exitMessage()); + } else { + emit resultRetrieved(m_process.readAllStandardOutput()); } - errorTermination(tr("%1 returned %2.").arg(executable).arg(m_process.exitCode())); - return; - } - m_running = false; - emit resultRetrieved(m_process.readAllStandardOutput()); - emit finished(); + emit finished(); + }); +} + +void QueryRunner::start() +{ + QTC_ASSERT(!m_process.isRunning(), return); + m_process.start(); } } // namespace GitLab diff --git a/src/plugins/gitlab/queryrunner.h b/src/plugins/gitlab/queryrunner.h index c002f9a5611..a60eb470ac7 100644 --- a/src/plugins/gitlab/queryrunner.h +++ b/src/plugins/gitlab/queryrunner.h @@ -62,24 +62,14 @@ class QueryRunner : public QObject Q_OBJECT public: QueryRunner(const Query &query, const Utils::Id &id, QObject *parent = nullptr); - ~QueryRunner(); - void start(); - void terminate(); signals: void finished(); void resultRetrieved(const QByteArray &json); private: - void errorTermination(const QString &msg); - void processError(QProcess::ProcessError error); - void processFinished(); - Utils::QtcProcess m_process; - Utils::Id m_serverId; - bool m_running = false; - bool m_paginated = false; }; } // namespace GitLab diff --git a/src/plugins/ios/iosconfigurations.cpp b/src/plugins/ios/iosconfigurations.cpp index d31687f8e15..23e2b01ef1a 100644 --- a/src/plugins/ios/iosconfigurations.cpp +++ b/src/plugins/ios/iosconfigurations.cpp @@ -238,7 +238,7 @@ static QByteArray decodeProvisioningProfile(const QString &path) p.runBlocking(); if (p.result() != ProcessResult::FinishedWithSuccess) qCDebug(iosCommonLog) << "Reading signed provisioning file failed" << path; - return p.stdOut().toLatin1(); + return p.cleanedStdOut().toLatin1(); } void IosConfigurations::updateAutomaticKitList() diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp index 49ae0a7cd20..4f09f556a07 100644 --- a/src/plugins/ios/iosprobe.cpp +++ b/src/plugins/ios/iosprobe.cpp @@ -72,7 +72,7 @@ void XcodeProbe::detectDeveloperPaths() qCWarning(probeLog) << QString::fromLatin1("Could not detect selected Xcode using xcode-select"); else - addDeveloperPath(selectedXcode.stdOut().trimmed()); + addDeveloperPath(selectedXcode.cleanedStdOut().trimmed()); addDeveloperPath(defaultDeveloperPath); } diff --git a/src/plugins/ios/simulatorcontrol.cpp b/src/plugins/ios/simulatorcontrol.cpp index f78f2839ce5..ca15e3c8918 100644 --- a/src/plugins/ios/simulatorcontrol.cpp +++ b/src/plugins/ios/simulatorcontrol.cpp @@ -85,7 +85,7 @@ static bool runCommand(const CommandLine &command, QString *stdOutput, QString * p.setCommand(command); p.runBlocking(); if (stdOutput) - *stdOutput = p.stdOut(); + *stdOutput = p.cleanedStdOut(); if (allOutput) *allOutput = p.allOutput(); return p.result() == ProcessResult::FinishedWithSuccess; diff --git a/src/plugins/languageclient/languageclientcompletionassist.cpp b/src/plugins/languageclient/languageclientcompletionassist.cpp index e10729987ce..0ab76a10c07 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.cpp +++ b/src/plugins/languageclient/languageclientcompletionassist.cpp @@ -227,6 +227,15 @@ bool LanguageClientCompletionItem::isPerfectMatch(int pos, QTextDocument *doc) c return textToInsert == textAt(QTextCursor(doc), pos - length, length); } +bool LanguageClientCompletionItem::isDeprecated() const +{ + if (const auto tags = m_item.tags(); tags && tags->contains(CompletionItem::Deprecated)) + return true; + if (const auto deprecated = m_item.deprecated()) + return *deprecated; + return false; +} + class LanguageClientCompletionModel : public GenericProposalModel { public: diff --git a/src/plugins/languageclient/languageclientcompletionassist.h b/src/plugins/languageclient/languageclientcompletionassist.h index 2f5ba014fab..19a8ec93063 100644 --- a/src/plugins/languageclient/languageclientcompletionassist.h +++ b/src/plugins/languageclient/languageclientcompletionassist.h @@ -135,6 +135,7 @@ public: bool operator <(const LanguageClientCompletionItem &other) const; bool isPerfectMatch(int pos, QTextDocument *doc) const; + bool isDeprecated() const; private: LanguageServerProtocol::CompletionItem m_item; diff --git a/src/plugins/languageclient/languageclientinterface.cpp b/src/plugins/languageclient/languageclientinterface.cpp index 5b7431cda00..c20fa7c121a 100644 --- a/src/plugins/languageclient/languageclientinterface.cpp +++ b/src/plugins/languageclient/languageclientinterface.cpp @@ -120,8 +120,12 @@ void StdIOClientInterface::startImpl() this, &StdIOClientInterface::readError); connect(m_process, &QtcProcess::readyReadStandardOutput, this, &StdIOClientInterface::readOutput); - connect(m_process, &QtcProcess::finished, this, &StdIOClientInterface::onProcessFinished); connect(m_process, &QtcProcess::started, this, &StdIOClientInterface::started); + connect(m_process, &QtcProcess::done, this, [this] { + if (m_process->result() != ProcessResult::FinishedWithSuccess) + emit error(m_process->exitMessage()); + emit finished(); + }); m_process->setCommand(m_cmd); m_process->setWorkingDirectory(m_workingDirectory); m_process->setEnvironment(m_env); @@ -155,15 +159,6 @@ void StdIOClientInterface::sendData(const QByteArray &data) m_process->writeRaw(data); } -void StdIOClientInterface::onProcessFinished() -{ - QTC_ASSERT(m_process, return); - if (m_process->exitStatus() == QProcess::CrashExit) - emit error(tr("Crashed with exit code %1: %2") - .arg(m_process->exitCode()).arg(m_process->errorString())); - emit finished(); -} - void StdIOClientInterface::readError() { QTC_ASSERT(m_process, return); diff --git a/src/plugins/languageclient/languageclientinterface.h b/src/plugins/languageclient/languageclientinterface.h index 083d7c3a675..0482c0e834b 100644 --- a/src/plugins/languageclient/languageclientinterface.h +++ b/src/plugins/languageclient/languageclientinterface.h @@ -97,7 +97,6 @@ protected: private: void readError(); void readOutput(); - void onProcessFinished(); }; } // namespace LanguageClient diff --git a/src/plugins/languageclient/semantichighlightsupport.cpp b/src/plugins/languageclient/semantichighlightsupport.cpp index 4cef4cd5cc8..a7aca308643 100644 --- a/src/plugins/languageclient/semantichighlightsupport.cpp +++ b/src/plugins/languageclient/semantichighlightsupport.cpp @@ -68,12 +68,16 @@ void SemanticTokenSupport::refresh() void SemanticTokenSupport::reloadSemanticTokens(TextDocument *textDocument) { - reloadSemanticTokensImpl(textDocument); + if (m_client->reachable()) + reloadSemanticTokensImpl(textDocument); + else + queueDocumentReload(textDocument); } void SemanticTokenSupport::reloadSemanticTokensImpl(TextDocument *textDocument, int remainingRerequests) { + m_docReloadQueue.remove(textDocument); const SemanticRequestTypes supportedRequests = supportedSemanticRequests(textDocument); if (supportedRequests.testFlag(SemanticRequestType::None)) return; @@ -122,7 +126,10 @@ void SemanticTokenSupport::reloadSemanticTokensImpl(TextDocument *textDocument, void SemanticTokenSupport::updateSemanticTokens(TextDocument *textDocument) { - updateSemanticTokensImpl(textDocument); + if (m_client->reachable()) + updateSemanticTokensImpl(textDocument); + else + queueDocumentReload(textDocument); } void SemanticTokenSupport::updateSemanticTokensImpl(TextDocument *textDocument, @@ -168,6 +175,22 @@ void SemanticTokenSupport::updateSemanticTokensImpl(TextDocument *textDocument, reloadSemanticTokens(textDocument); } +void SemanticTokenSupport::queueDocumentReload(TextEditor::TextDocument *doc) +{ + if (m_docReloadQueue.contains(doc)) + return; + m_docReloadQueue << doc; + connect( + m_client, + &Client::initialized, + this, + [this, doc = QPointer(doc)]() { + if (doc) + reloadSemanticTokensImpl(doc); + }, + Qt::QueuedConnection); +} + void SemanticTokenSupport::clearHighlight(TextEditor::TextDocument *doc) { if (m_tokens.contains(doc->filePath())){ diff --git a/src/plugins/languageclient/semantichighlightsupport.h b/src/plugins/languageclient/semantichighlightsupport.h index e903fe58f94..a03947c9153 100644 --- a/src/plugins/languageclient/semantichighlightsupport.h +++ b/src/plugins/languageclient/semantichighlightsupport.h @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -86,6 +87,7 @@ public: private: void reloadSemanticTokensImpl(TextEditor::TextDocument *doc, int remainingRerequests = 3); void updateSemanticTokensImpl(TextEditor::TextDocument *doc, int remainingRerequests = 3); + void queueDocumentReload(TextEditor::TextDocument *doc); LanguageServerProtocol::SemanticRequestTypes supportedSemanticRequests( TextEditor::TextDocument *document) const; void handleSemanticTokens(const Utils::FilePath &filePath, @@ -117,6 +119,7 @@ private: SemanticTokensHandler m_tokensHandler; QStringList m_tokenTypeStrings; QStringList m_tokenModifierStrings; + QSet m_docReloadQueue; }; } // namespace LanguageClient diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index c4d7f89abb3..ddf930ba1c6 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -103,7 +103,7 @@ bool MercurialClient::manifestSync(const FilePath &repository, const QString &re const QDir repositoryDir(repository.toString()); const QFileInfo needle = QFileInfo(repositoryDir, relativeFilename); - const QStringList files = proc.stdOut().split(QLatin1Char('\n')); + const QStringList files = proc.cleanedStdOut().split(QLatin1Char('\n')); for (const QString &fileName : files) { const QFileInfo managedFile(repositoryDir, fileName); if (needle == managedFile) @@ -186,7 +186,7 @@ bool MercurialClient::synchronousPull(const FilePath &workingDir, const QString const bool ok = proc.result() == ProcessResult::FinishedWithSuccess; - parsePullOutput(proc.stdOut().trimmed()); + parsePullOutput(proc.cleanedStdOut().trimmed()); return ok; } @@ -232,16 +232,16 @@ changeset: 0:031a48610fba user: ... \endcode */ // Obtain first line and split by blank-delimited tokens - const QStringList lines = proc.stdOut().split(QLatin1Char('\n')); + const QStringList lines = proc.cleanedStdOut().split(QLatin1Char('\n')); if (lines.size() < 1) { VcsOutputWindow::appendSilently( - msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(proc.stdOut()))); + msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(proc.cleanedStdOut()))); return QStringList(); } QStringList changeSets = lines.front().simplified().split(QLatin1Char(' ')); if (changeSets.size() < 2) { VcsOutputWindow::appendSilently( - msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(proc.stdOut()))); + msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(proc.cleanedStdOut()))); return QStringList(); } // Remove revision numbers @@ -270,7 +270,7 @@ QString MercurialClient::shortDescriptionSync(const FilePath &workingDirectory, vcsFullySynchronousExec(proc, workingDirectory, args); if (proc.result() != ProcessResult::FinishedWithSuccess) return revision; - return stripLastNewline(proc.stdOut()); + return stripLastNewline(proc.cleanedStdOut()); } // Default format: "SHA1 (author summmary)" @@ -288,7 +288,7 @@ bool MercurialClient::managesFile(const FilePath &workingDirectory, const QStrin args << QLatin1String("status") << QLatin1String("--unknown") << fileName; QtcProcess proc; vcsFullySynchronousExec(proc, workingDirectory, args); - return proc.stdOut().isEmpty(); + return proc.cleanedStdOut().isEmpty(); } void MercurialClient::incoming(const FilePath &repositoryRoot, const QString &repository) diff --git a/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.cpp b/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.cpp index d13175f5f4f..48579c8d074 100644 --- a/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.cpp +++ b/src/plugins/mesonprojectmanager/exewrappers/toolwrapper.cpp @@ -66,7 +66,7 @@ Version ToolWrapper::read_version(const Utils::FilePath &toolPath) process.setCommand({ toolPath, { "--version" } }); process.start(); if (process.waitForFinished()) - return Version::fromString(process.stdOut()); + return Version::fromString(process.cleanedStdOut()); } return {}; } diff --git a/src/plugins/nim/project/nimblebuildsystem.cpp b/src/plugins/nim/project/nimblebuildsystem.cpp index 7a2a642eebc..634012cb42f 100644 --- a/src/plugins/nim/project/nimblebuildsystem.cpp +++ b/src/plugins/nim/project/nimblebuildsystem.cpp @@ -63,7 +63,7 @@ static std::vector parseTasks(const FilePath &nimblePath, const File std::vector result; if (process.exitCode() != 0) { - TaskHub::addTask(Task(Task::Error, process.stdOut(), {}, -1, Constants::C_NIMPARSE_ID)); + TaskHub::addTask(Task(Task::Error, process.cleanedStdOut(), {}, -1, Constants::C_NIMPARSE_ID)); return result; } @@ -91,7 +91,7 @@ static NimbleMetadata parseMetadata(const FilePath &nimblePath, const FilePath & NimbleMetadata result = {}; if (process.exitCode() != 0) { - TaskHub::addTask(Task(Task::Error, process.stdOut(), {}, -1, Constants::C_NIMPARSE_ID)); + TaskHub::addTask(Task(Task::Error, process.cleanedStdOut(), {}, -1, Constants::C_NIMPARSE_ID)); return result; } const QList &lines = linesFromProcessOutput(&process); diff --git a/src/plugins/nim/suggest/nimsuggest.cpp b/src/plugins/nim/suggest/nimsuggest.cpp index e51efea0545..fc12c160233 100644 --- a/src/plugins/nim/suggest/nimsuggest.cpp +++ b/src/plugins/nim/suggest/nimsuggest.cpp @@ -32,8 +32,7 @@ NimSuggest::NimSuggest(QObject *parent) : QObject(parent) { connect(&m_server, &NimSuggestServer::started, this, &NimSuggest::onServerStarted); - connect(&m_server, &NimSuggestServer::crashed, this, &NimSuggest::onServerCrashed); - connect(&m_server, &NimSuggestServer::finished, this, &NimSuggest::onServerFinished); + connect(&m_server, &NimSuggestServer::done, this, &NimSuggest::onServerDone); connect(&m_client, &NimSuggestClient::disconnected, this, &NimSuggest::onClientDisconnected); connect(&m_client, &NimSuggestClient::connected, this, &NimSuggest::onClientConnected); @@ -134,14 +133,13 @@ void NimSuggest::disconnectClient() void NimSuggest::stopServer() { - m_server.kill(); + m_server.stop(); } void NimSuggest::startServer() { - if (!m_projectFile.isEmpty() && !m_executablePath.isEmpty()) { + if (!m_projectFile.isEmpty() && !m_executablePath.isEmpty()) m_server.start(m_executablePath, m_projectFile); - } } void NimSuggest::onServerStarted() @@ -150,18 +148,13 @@ void NimSuggest::onServerStarted() connectClient(); } -void NimSuggest::onServerCrashed() +void NimSuggest::onServerDone() { setServerReady(false); disconnectClient(); restart(); } -void NimSuggest::onServerFinished() -{ - onServerCrashed(); -} - void NimSuggest::onClientConnected() { setClientReady(true); diff --git a/src/plugins/nim/suggest/nimsuggest.h b/src/plugins/nim/suggest/nimsuggest.h index 5043455cec3..48190496ab2 100644 --- a/src/plugins/nim/suggest/nimsuggest.h +++ b/src/plugins/nim/suggest/nimsuggest.h @@ -75,8 +75,7 @@ private: void startServer(); void onServerStarted(); - void onServerCrashed(); - void onServerFinished(); + void onServerDone(); void onClientConnected(); void onClientDisconnected(); diff --git a/src/plugins/nim/suggest/server.cpp b/src/plugins/nim/suggest/server.cpp index 48e29d1ceb7..e55151afbe8 100644 --- a/src/plugins/nim/suggest/server.cpp +++ b/src/plugins/nim/suggest/server.cpp @@ -32,17 +32,11 @@ namespace Suggest { NimSuggestServer::NimSuggestServer(QObject *parent) : QObject(parent) { - connect(&m_process, &QtcProcess::finished, this, &NimSuggestServer::onFinished); - connect(&m_process, &QtcProcess::started, this, &NimSuggestServer::onStarted); + connect(&m_process, &QtcProcess::done, this, &NimSuggestServer::onDone); connect(&m_process, &QtcProcess::readyReadStandardOutput, this, &NimSuggestServer::onStandardOutputAvailable); } -NimSuggestServer::~NimSuggestServer() -{ - kill(); -} - QString NimSuggestServer::executablePath() const { return m_executablePath; @@ -61,7 +55,7 @@ bool NimSuggestServer::start(const QString &executablePath, return false; } - m_port = 0; + stop(); m_executablePath = executablePath; m_projectFilePath = projectFilePath; m_process.setCommand({FilePath::fromString(executablePath), {"--epc", m_projectFilePath}}); @@ -69,11 +63,9 @@ bool NimSuggestServer::start(const QString &executablePath, return true; } -void NimSuggestServer::kill() +void NimSuggestServer::stop() { - disconnect(&m_process, &QtcProcess::finished, this, &NimSuggestServer::onFinished); - m_process.kill(); - m_process.waitForFinished(); + m_process.close(); clearState(); } @@ -87,15 +79,10 @@ QString NimSuggestServer::projectFilePath() const return m_projectFilePath; } -void NimSuggestServer::onStarted() -{ - m_started = true; -} - void NimSuggestServer::onStandardOutputAvailable() { - if (m_started && !m_portAvailable) { - auto output = QString::fromUtf8(m_process.readAllStandardOutput()); + if (!m_portAvailable) { + const QString output = QString::fromUtf8(m_process.readAllStandardOutput()); m_port = static_cast(output.toUInt()); m_portAvailable = true; emit started(); @@ -104,19 +91,14 @@ void NimSuggestServer::onStandardOutputAvailable() } } -void NimSuggestServer::onFinished() +void NimSuggestServer::onDone() { clearState(); - - if (m_process.exitStatus() == QProcess::CrashExit) - emit crashed(); - else - emit finished(); + emit done(); } void NimSuggestServer::clearState() { - m_started = false; m_portAvailable = false; m_port = 0; } diff --git a/src/plugins/nim/suggest/server.h b/src/plugins/nim/suggest/server.h index 53f0590288a..4d3a5857ef0 100644 --- a/src/plugins/nim/suggest/server.h +++ b/src/plugins/nim/suggest/server.h @@ -40,10 +40,9 @@ class NimSuggestServer : public QObject public: NimSuggestServer(QObject *parent = nullptr); - ~NimSuggestServer(); bool start(const QString &executablePath, const QString &projectFilePath); - void kill(); + void stop(); quint16 port() const; QString executablePath() const; @@ -51,16 +50,13 @@ public: signals: void started(); - void finished(); - void crashed(); + void done(); private: - void onStarted(); void onStandardOutputAvailable(); - void onFinished(); + void onDone(); void clearState(); - bool m_started = false; bool m_portAvailable = false; Utils::QtcProcess m_process; quint16 m_port = 0; diff --git a/src/plugins/perforce/perforcechecker.cpp b/src/plugins/perforce/perforcechecker.cpp index 3dc7f73d504..8ce4f04d395 100644 --- a/src/plugins/perforce/perforcechecker.cpp +++ b/src/plugins/perforce/perforcechecker.cpp @@ -127,11 +127,11 @@ void PerforceChecker::slotDone() break; case QProcess::NormalExit: if (m_process.exitCode()) { - const QString stdErr = m_process.stdErr(); + const QString stdErr = m_process.cleanedStdErr(); emitFailed(tr("\"%1\" terminated with exit code %2: %3"). arg(m_binary.toUserOutput()).arg(m_process.exitCode()).arg(stdErr)); } else { - parseOutput(m_process.stdOut()); + parseOutput(m_process.cleanedStdOut()); } break; } diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 4c7039d2606..84ecf557214 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -1277,8 +1277,8 @@ PerforceResponse PerforcePluginPrivate::synchronousProcess(const FilePath &worki PerforceResponse response; response.error = true; response.exitCode = process.exitCode(); - response.stdErr = process.stdErr(); - response.stdOut = process.stdOut(); + response.stdErr = process.cleanedStdErr(); + response.stdOut = process.cleanedStdOut(); switch (process.result()) { case ProcessResult::FinishedWithSuccess: response.error = false; diff --git a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp index 0b834009493..c5f801cc8e4 100644 --- a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp @@ -118,7 +118,7 @@ static bool process.runBlocking(EventLoopMode::On); if (process.result() != Utils::ProcessResult::FinishedWithSuccess) { *errorMessage = QString("Generator script failed: %1").arg(process.exitMessage()); - const QString stdErr = process.stdErr(); + const QString stdErr = process.cleanedStdErr(); if (!stdErr.isEmpty()) { errorMessage->append(QLatin1Char('\n')); errorMessage->append(stdErr); @@ -126,7 +126,7 @@ static bool return false; } if (stdOut) { - *stdOut = process.stdOut(); + *stdOut = process.cleanedStdOut(); if (CustomWizard::verbose()) qDebug("Output: '%s'\n", qPrintable(*stdOut)); } diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp index a9ab24c39b8..da69611151f 100644 --- a/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp +++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocesslist.cpp @@ -68,12 +68,12 @@ void SshDeviceProcessList::doKillProcess(const ProcessInfo &process) void SshDeviceProcessList::handleProcessDone() { if (d->m_process.result() == ProcessResult::FinishedWithSuccess) { - reportProcessListUpdated(buildProcessList(d->m_process.stdOut())); + reportProcessListUpdated(buildProcessList(d->m_process.cleanedStdOut())); } else { const QString errorMessage = d->m_process.exitStatus() == QProcess::NormalExit ? tr("Process listing command failed with exit code %1.").arg(d->m_process.exitCode()) : d->m_process.errorString(); - const QString stdErr = d->m_process.stdErr(); + const QString stdErr = d->m_process.cleanedStdErr(); const QString fullMessage = stdErr.isEmpty() ? errorMessage : errorMessage + '\n' + tr("Remote stderr was: %1").arg(stdErr); reportError(fullMessage); diff --git a/src/plugins/projectexplorer/gcctoolchain.cpp b/src/plugins/projectexplorer/gcctoolchain.cpp index 355ff2d7fc6..fa62339215d 100644 --- a/src/plugins/projectexplorer/gcctoolchain.cpp +++ b/src/plugins/projectexplorer/gcctoolchain.cpp @@ -442,6 +442,8 @@ static QStringList filteredFlags(const QStringList &allFlags, bool considerSysro } else if (a == "-arch") { if (++i < allFlags.length() && !filtered.contains(a)) filtered << a << allFlags.at(i); + } else if (a == "-Xclang") { + filtered << a; } else if ((considerSysroot && (a == "--sysroot" || a == "-isysroot")) || a == "-D" || a == "-U" || a == "-gcc-toolchain" || a == "-target" || a == "-mllvm" || a == "-isystem") { @@ -1590,7 +1592,7 @@ bool ClangToolChain::matchesCompilerCommand(const Utils::FilePath &command, std::unique_ptr xcrun(new QtcProcess); xcrun->setCommand({"/usr/bin/xcrun", {"-f", compilerCommand().fileName()}}); xcrun->runBlocking(); - const FilePath output = FilePath::fromString(xcrun->stdOut().trimmed()); + const FilePath output = FilePath::fromString(xcrun->cleanedStdOut().trimmed()); if (output.isExecutableFile() && output != compilerCommand()) m_resolvedCompilerCommand = output; } diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index 9f456a8b06c..cd76162d402 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -31,7 +31,6 @@ #include "projectexplorerconstants.h" #include "projectexplorersettings.h" #include "taskhub.h" -#include "toolchainmanager.h" #include @@ -106,7 +105,10 @@ const MsvcPlatform platforms[] {MsvcToolChain::amd64_arm, "amd64_arm", "/bin/amd64_arm", "vcvarsamd64_arm.bat"}, {MsvcToolChain::amd64_x86, "amd64_x86", "/bin/amd64_x86", "vcvarsamd64_x86.bat"}, {MsvcToolChain::x86_arm64, "x86_arm64", "/bin/x86_arm64", "vcvarsx86_arm64.bat"}, - {MsvcToolChain::amd64_arm64, "amd64_arm64", "/bin/amd64_arm64", "vcvarsamd64_arm64.bat"}}; + {MsvcToolChain::amd64_arm64, "amd64_arm64", "/bin/amd64_arm64", "vcvarsamd64_arm64.bat"}, + {MsvcToolChain::arm64, "arm64", "/bin/arm64", "vcvarsarm64.bat"}, + {MsvcToolChain::arm64_x86, "arm64_x86", "/bin/arm64_x86", "vcvarsarm64_x86.bat"}, + {MsvcToolChain::arm64_amd64, "arm64_amd64", "/bin/arm64_amd64", "vcvarsarm64_amd64.bat"}}; static QList g_availableMsvcToolchains; @@ -147,6 +149,9 @@ static bool hostPrefersPlatform(MsvcToolChain::Platform platform) || platform == MsvcToolChain::x86_arm64; case HostOsInfo::HostArchitectureArm: return platform == MsvcToolChain::arm; + case HostOsInfo::HostArchitectureArm64: + return platform == MsvcToolChain::arm64 + || platform == MsvcToolChain::arm64_x86 || platform == MsvcToolChain::arm64_amd64; case HostOsInfo::HostArchitectureItanium: return platform == MsvcToolChain::ia64; default: @@ -167,7 +172,7 @@ static bool hostSupportsPlatform(MsvcToolChain::Platform platform) || platform == MsvcToolChain::x86_ia64 || platform == MsvcToolChain::x86_arm || platform == MsvcToolChain::x86_arm64; // The Arm64 host can run the cross-compilers via emulation of x86 and amd64 - case HostOsInfo::HostArchitectureArm: + case HostOsInfo::HostArchitectureArm64: return platform == MsvcToolChain::x86_arm || platform == MsvcToolChain::x86_arm64 || platform == MsvcToolChain::amd64_arm || platform == MsvcToolChain::amd64_arm64 || platform == MsvcToolChain::x86 || platform == MsvcToolChain::x86_amd64 @@ -296,7 +301,7 @@ static QVector detectVisualStudioFromVsWhere(const QSt return installations; } - QByteArray output = vsWhereProcess.stdOut().toUtf8(); + QByteArray output = vsWhereProcess.cleanedStdOut().toUtf8(); QJsonParseError error; const QJsonDocument doc = QJsonDocument::fromJson(output, &error); if (error.error != QJsonParseError::NoError || doc.isNull()) { @@ -394,6 +399,7 @@ static unsigned char wordWidthForPlatform(MsvcToolChain::Platform platform) case ProjectExplorer::Internal::MsvcToolChain::x86_arm: case ProjectExplorer::Internal::MsvcToolChain::amd64_arm: case ProjectExplorer::Internal::MsvcToolChain::amd64_x86: + case ProjectExplorer::Internal::MsvcToolChain::arm64_x86: return 32; case ProjectExplorer::Internal::MsvcToolChain::amd64: case ProjectExplorer::Internal::MsvcToolChain::x86_amd64: @@ -401,6 +407,8 @@ static unsigned char wordWidthForPlatform(MsvcToolChain::Platform platform) case ProjectExplorer::Internal::MsvcToolChain::x86_ia64: case ProjectExplorer::Internal::MsvcToolChain::amd64_arm64: case ProjectExplorer::Internal::MsvcToolChain::x86_arm64: + case ProjectExplorer::Internal::MsvcToolChain::arm64: + case ProjectExplorer::Internal::MsvcToolChain::arm64_amd64: return 64; } @@ -414,12 +422,15 @@ static Abi::Architecture archForPlatform(MsvcToolChain::Platform platform) case ProjectExplorer::Internal::MsvcToolChain::amd64: case ProjectExplorer::Internal::MsvcToolChain::x86_amd64: case ProjectExplorer::Internal::MsvcToolChain::amd64_x86: + case ProjectExplorer::Internal::MsvcToolChain::arm64_x86: + case ProjectExplorer::Internal::MsvcToolChain::arm64_amd64: return Abi::X86Architecture; case ProjectExplorer::Internal::MsvcToolChain::arm: case ProjectExplorer::Internal::MsvcToolChain::x86_arm: case ProjectExplorer::Internal::MsvcToolChain::amd64_arm: case ProjectExplorer::Internal::MsvcToolChain::x86_arm64: case ProjectExplorer::Internal::MsvcToolChain::amd64_arm64: + case ProjectExplorer::Internal::MsvcToolChain::arm64: return Abi::ArmArchitecture; case ProjectExplorer::Internal::MsvcToolChain::ia64: case ProjectExplorer::Internal::MsvcToolChain::x86_ia64: @@ -667,7 +678,7 @@ Macros MsvcToolChain::msvcPredefinedMacros(const QStringList &cxxflags, if (cpp.result() != ProcessResult::FinishedWithSuccess) return predefinedMacros; - const QStringList output = Utils::filtered(cpp.stdOut().split('\n'), + const QStringList output = Utils::filtered(cpp.cleanedStdOut().split('\n'), [](const QString &s) { return s.startsWith('V'); }); for (const QString &line : output) predefinedMacros.append(Macro::fromKeyValue(line.mid(1))); @@ -1325,6 +1336,9 @@ MsvcToolChainConfigWidget::MsvcToolChainConfigWidget(ToolChain *tc) m_varsBatArchCombo->addItem("amd64_arm64", MsvcToolChain::amd64_arm64); m_varsBatArchCombo->addItem("ia64", MsvcToolChain::ia64); m_varsBatArchCombo->addItem("x86_ia64", MsvcToolChain::x86_ia64); + m_varsBatArchCombo->addItem("arm64", MsvcToolChain::arm64); + m_varsBatArchCombo->addItem("arm64_x86", MsvcToolChain::arm64_x86); + m_varsBatArchCombo->addItem("arm64_amd64", MsvcToolChain::arm64_amd64); m_varsBatArgumentsEdit->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); m_varsBatArgumentsEdit->setToolTip(tr("Additional arguments for the vcvarsall.bat call")); hLayout->addWidget(m_varsBatPathCombo); @@ -1555,7 +1569,7 @@ static QVersionNumber clangClVersion(const FilePath &clangClPath) return {}; const QRegularExpressionMatch match = QRegularExpression( QStringLiteral("clang version (\\d+(\\.\\d+)+)")) - .match(clangClProcess.stdOut()); + .match(clangClProcess.cleanedStdOut()); if (!match.hasMatch()) return {}; return QVersionNumber::fromString(match.captured(1)); @@ -1940,6 +1954,7 @@ Toolchains MsvcToolChainFactory::autoDetect(const ToolchainDetector &detector) c {MsvcToolChain::x86, "x86"}, {MsvcToolChain::amd64, "x64"}, {MsvcToolChain::ia64, "ia64"}, + {MsvcToolChain::arm64, "arm64"}, }; for (const auto &platform : platforms) { tmp.append(findOrCreateToolchains(detector, @@ -1975,7 +1990,10 @@ Toolchains MsvcToolChainFactory::autoDetect(const ToolchainDetector &detector) c MsvcToolChain::x86_arm64, MsvcToolChain::amd64_arm64, MsvcToolChain::ia64, - MsvcToolChain::x86_ia64}; + MsvcToolChain::x86_ia64, + MsvcToolChain::arm64, + MsvcToolChain::arm64_x86, + MsvcToolChain::arm64_amd64}; const QVector studios = detectVisualStudio(); for (const VisualStudioInstallation &i : studios) { @@ -2127,7 +2145,7 @@ Utils::optional MsvcToolChain::generateEnvironmentSettings(const Utils: run.runBlocking(); if (run.result() != ProcessResult::FinishedWithSuccess) { - const QString message = !run.stdErr().isEmpty() ? run.stdErr() : run.exitMessage(); + const QString message = !run.cleanedStdErr().isEmpty() ? run.cleanedStdErr() : run.exitMessage(); qWarning().noquote() << message; QString command = QDir::toNativeSeparators(batchFile); if (!batchArgs.isEmpty()) @@ -2139,7 +2157,7 @@ Utils::optional MsvcToolChain::generateEnvironmentSettings(const Utils: } // The SDK/MSVC scripts do not return exit codes != 0. Check on stdout. - const QString stdOut = run.stdOut(); + const QString stdOut = run.cleanedStdOut(); // // Now parse the file to get the environment settings diff --git a/src/plugins/projectexplorer/msvctoolchain.h b/src/plugins/projectexplorer/msvctoolchain.h index 56c926141c5..05090e721b5 100644 --- a/src/plugins/projectexplorer/msvctoolchain.h +++ b/src/plugins/projectexplorer/msvctoolchain.h @@ -28,7 +28,6 @@ #include "abi.h" #include "abiwidget.h" #include "toolchain.h" -#include "toolchaincache.h" #include "toolchainconfigwidget.h" #include @@ -58,7 +57,7 @@ class MsvcToolChain : public ToolChain public: enum Type { WindowsSDK, VS }; enum Platform { x86, amd64, x86_amd64, ia64, x86_ia64, arm, x86_arm, amd64_arm, amd64_x86, - x86_arm64, amd64_arm64 }; + x86_arm64, amd64_arm64, arm64, arm64_x86, arm64_amd64 }; explicit MsvcToolChain(Utils::Id typeId); ~MsvcToolChain() override; diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index b826b215698..f8da814b7a6 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -1379,7 +1379,7 @@ void SimpleTargetRunnerPrivate::handleStandardOutput() const QByteArray data = m_process.readAllStandardOutput(); const QString msg = m_outputCodec->toUnicode( data.constData(), data.length(), &m_outputCodecState); - q->appendMessage(msg, StdOutFormat, false); + q->appendMessageChunk(msg, StdOutFormat); } void SimpleTargetRunnerPrivate::handleStandardError() @@ -1387,7 +1387,7 @@ void SimpleTargetRunnerPrivate::handleStandardError() const QByteArray data = m_process.readAllStandardError(); const QString msg = m_outputCodec->toUnicode( data.constData(), data.length(), &m_errorCodecState); - q->appendMessage(msg, StdErrFormat, false); + q->appendMessageChunk(msg, StdErrFormat); } void SimpleTargetRunnerPrivate::start() @@ -1766,14 +1766,19 @@ void RunWorker::reportFailure(const QString &msg) * Appends a message in the specified \a format to * the owning RunControl's \uicontrol{Application Output} pane. */ -void RunWorker::appendMessage(const QString &msg, OutputFormat format, bool appendNewLine) +void RunWorker::appendMessage(const QString &msg, OutputFormat format) { - if (!appendNewLine || msg.endsWith('\n')) + if (msg.endsWith('\n')) emit d->runControl->appendMessage(msg, format); else emit d->runControl->appendMessage(msg + '\n', format); } +void RunWorker::appendMessageChunk(const QString &msg, OutputFormat format) +{ + emit d->runControl->appendMessage(msg, format); +} + IDevice::ConstPtr RunWorker::device() const { return d->runControl->device(); diff --git a/src/plugins/projectexplorer/runcontrol.h b/src/plugins/projectexplorer/runcontrol.h index ebb0ec54a0b..0ff9b8778e9 100644 --- a/src/plugins/projectexplorer/runcontrol.h +++ b/src/plugins/projectexplorer/runcontrol.h @@ -92,7 +92,8 @@ public: QVariant recordedData(const QString &channel) const; // Part of read-only interface of RunControl for convenience. - void appendMessage(const QString &msg, Utils::OutputFormat format, bool appendNewLine = true); + void appendMessage(const QString &msg, Utils::OutputFormat format); + void appendMessageChunk(const QString &msg, Utils::OutputFormat format); IDeviceConstPtr device() const; // States diff --git a/src/plugins/projectexplorer/taskhub.cpp b/src/plugins/projectexplorer/taskhub.cpp index 02d1f713e60..d8962d8fc9c 100644 --- a/src/plugins/projectexplorer/taskhub.cpp +++ b/src/plugins/projectexplorer/taskhub.cpp @@ -154,7 +154,7 @@ 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] { + QMetaObject::invokeMethod(qApp, [task = std::move(task)] { TaskHub::addTask(task); }); diff --git a/src/plugins/python/pipsupport.cpp b/src/plugins/python/pipsupport.cpp index 44ee82727c0..b290f75d2ee 100644 --- a/src/plugins/python/pipsupport.cpp +++ b/src/plugins/python/pipsupport.cpp @@ -47,10 +47,16 @@ namespace Internal { static constexpr char pipInstallTaskId[] = "Python::pipInstallTask"; -PipInstallTask::PipInstallTask(const Utils::FilePath &python) +PipInstallTask::PipInstallTask(const FilePath &python) : m_python(python) { m_watcher.setFuture(m_future.future()); + + connect(&m_process, &QtcProcess::done, this, &PipInstallTask::handleDone); + connect(&m_process, &QtcProcess::readyReadStandardError, this, &PipInstallTask::handleError); + connect(&m_process, &QtcProcess::readyReadStandardOutput, this, &PipInstallTask::handleOutput); + connect(&m_killTimer, &QTimer::timeout, this, &PipInstallTask::cancel); + connect(&m_watcher, &QFutureWatcher::canceled, this, &PipInstallTask::cancel); } void PipInstallTask::setPackage(const PipPackage &package) @@ -66,13 +72,6 @@ void PipInstallTask::run() } const QString taskTitle = tr("Install %1").arg(m_package.displayName); Core::ProgressManager::addTask(m_future.future(), taskTitle, pipInstallTaskId); - connect(&m_process, &QtcProcess::finished, this, &PipInstallTask::installFinished); - connect(&m_process, &QtcProcess::readyReadStandardError, this, &PipInstallTask::handleError); - connect(&m_process, &QtcProcess::readyReadStandardOutput, this, &PipInstallTask::handleOutput); - - connect(&m_killTimer, &QTimer::timeout, this, &PipInstallTask::cancel); - connect(&m_watcher, &QFutureWatcher::canceled, this, &PipInstallTask::cancel); - QString package = m_package.packageName; if (!m_package.version.isEmpty()) package += "==" + m_package.version; @@ -102,13 +101,12 @@ void PipInstallTask::cancel() .arg(m_package.displayName, m_killTimer.isActive() ? tr("user") : tr("time out"))); } -void PipInstallTask::installFinished() +void PipInstallTask::handleDone() { m_future.reportFinished(); const bool success = m_process.result() == ProcessResult::FinishedWithSuccess; if (!success) { - Core::MessageManager::writeFlashing( - tr("Installing the %1 failed with exit code %2") + Core::MessageManager::writeFlashing(tr("Installing the %1 failed with exit code %2") .arg(m_package.displayName).arg(m_process.exitCode())); } emit finished(success); @@ -128,7 +126,7 @@ void PipInstallTask::handleError() Core::MessageManager::writeSilently(stdErr); } -PipPackageInfo PipPackage::info(const Utils::FilePath &python) const +PipPackageInfo PipPackage::info(const FilePath &python) const { PipPackageInfo result; diff --git a/src/plugins/python/pipsupport.h b/src/plugins/python/pipsupport.h index 24db560b61a..9aeded08ab0 100644 --- a/src/plugins/python/pipsupport.h +++ b/src/plugins/python/pipsupport.h @@ -84,7 +84,7 @@ signals: private: void cancel(); - void installFinished(); + void handleDone(); void handleOutput(); void handleError(); diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index 6965305f2e6..2bdfebc2783 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -106,6 +106,10 @@ void PySideInstaller::installPyside(const Utils::FilePath &python, auto install = new PipInstallTask(python); connect(install, &PipInstallTask::finished, install, &QObject::deleteLater); + connect(install, &PipInstallTask::finished, this, [=](bool success){ + if (success) + emit pySideInstalled(python, pySide); + }); install->setPackage(PipPackage(pySide)); install->run(); } diff --git a/src/plugins/python/pyside.h b/src/plugins/python/pyside.h index f749399903f..d396c726b4a 100644 --- a/src/plugins/python/pyside.h +++ b/src/plugins/python/pyside.h @@ -40,13 +40,17 @@ namespace Internal { class PySideInstaller : public QObject { - Q_DECLARE_TR_FUNCTIONS(Python::Internal::PySideInstaller) + Q_OBJECT public: static PySideInstaller *instance(); static void checkPySideInstallation(const Utils::FilePath &python, TextEditor::TextDocument *document); + +signals: + void pySideInstalled(const Utils::FilePath &python, const QString &pySide); + private: PySideInstaller(); diff --git a/src/plugins/python/pythonlanguageclient.cpp b/src/plugins/python/pythonlanguageclient.cpp index b129a069049..2a4ea8c7d97 100644 --- a/src/plugins/python/pythonlanguageclient.cpp +++ b/src/plugins/python/pythonlanguageclient.cpp @@ -181,9 +181,9 @@ PyLSClient *clientForPython(const FilePath &python) return client; } -PyLSClient::PyLSClient(BaseClientInterface *interface) +PyLSClient::PyLSClient(PyLSInterface *interface) : Client(interface) - , m_extraCompilerOutputDir(static_cast(interface)->m_extraPythonPath.path()) + , m_extraCompilerOutputDir(interface->m_extraPythonPath.path()) { connect(this, &Client::initialized, this, &PyLSClient::updateConfiguration); connect(PythonSettings::instance(), &PythonSettings::pylsConfigurationChanged, diff --git a/src/plugins/python/pythonlanguageclient.h b/src/plugins/python/pythonlanguageclient.h index ed0c16b5893..c58103c5fbf 100644 --- a/src/plugins/python/pythonlanguageclient.h +++ b/src/plugins/python/pythonlanguageclient.h @@ -40,12 +40,13 @@ namespace Internal { class PySideUicExtraCompiler; class PythonLanguageServerState; +class PyLSInterface; class PyLSClient : public LanguageClient::Client { Q_OBJECT public: - explicit PyLSClient(LanguageClient::BaseClientInterface *interface); + explicit PyLSClient(PyLSInterface *interface); ~PyLSClient(); void openDocument(TextEditor::TextDocument *document) override; diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index a04d2b723a7..5f63c19091f 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -202,6 +202,12 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Id id) setRunnableModifier([](Runnable &r) { r.workingDirectory = r.workingDirectory.onDevice(r.command.executable()); }); + + connect(PySideInstaller::instance(), &PySideInstaller::pySideInstalled, this, + [this](const FilePath &python) { + if (python == aspect()->currentInterpreter().command) + checkForPySide(python); + }); } PythonRunConfiguration::~PythonRunConfiguration() @@ -209,9 +215,8 @@ PythonRunConfiguration::~PythonRunConfiguration() qDeleteAll(m_extraCompilers); } -void PythonRunConfiguration::currentInterpreterChanged() +void PythonRunConfiguration::checkForPySide(const FilePath &python) { - const FilePath python = aspect()->currentInterpreter().command; BuildStepList *buildSteps = target()->activeBuildConfiguration()->buildSteps(); Utils::FilePath pySideProjectPath; @@ -236,7 +241,12 @@ void PythonRunConfiguration::currentInterpreterChanged() // Workaround that pip might return an incomplete file list on windows if (HostOsInfo::isWindowsHost() && !python.needsDevice() && !info.location.isEmpty() && m_pySideUicPath.isEmpty()) { - const FilePath scripts = info.location.parentDir().pathAppended("Scripts"); + // Scripts is next to the site-packages install dir for user installations + FilePath scripts = info.location.parentDir().pathAppended("Scripts"); + if (!scripts.exists()) { + // in global/venv installations Scripts is next to Lib/site-packages + scripts = info.location.parentDir().parentDir().pathAppended("Scripts"); + } auto userInstalledPySideTool = [&](const QString &toolName) { const FilePath tool = scripts.pathAppended(HostOsInfo::withExecutableSuffix(toolName)); return tool.isExecutableFile() ? tool : FilePath(); @@ -250,6 +260,12 @@ void PythonRunConfiguration::currentInterpreterChanged() if (auto pySideBuildStep = buildSteps->firstOfType()) pySideBuildStep->updatePySideProjectPath(pySideProjectPath); +} + +void PythonRunConfiguration::currentInterpreterChanged() +{ + const FilePath python = aspect()->currentInterpreter().command; + checkForPySide(python); for (FilePath &file : project()->files(Project::AllFiles)) { if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) { diff --git a/src/plugins/python/pythonrunconfiguration.h b/src/plugins/python/pythonrunconfiguration.h index 5394896b948..89bddac83e2 100644 --- a/src/plugins/python/pythonrunconfiguration.h +++ b/src/plugins/python/pythonrunconfiguration.h @@ -43,6 +43,7 @@ public: QList extraCompilers() const; private: + void checkForPySide(const Utils::FilePath &python); void updateExtraCompilers(); Utils::FilePath m_pySideUicPath; diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index e861e4c46b8..c8e77b0e538 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -78,7 +78,7 @@ static Interpreter createInterpreter(const FilePath &python, pythonProcess.setCommand({python, {"--version"}}); pythonProcess.runBlocking(); if (pythonProcess.result() == ProcessResult::FinishedWithSuccess) - result.name = pythonProcess.stdOut().trimmed(); + result.name = pythonProcess.cleanedStdOut().trimmed(); if (result.name.isEmpty()) result.name = defaultName; if (windowedSuffix) diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index 08c8750c21f..ebc2a695f7b 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -74,13 +74,22 @@ FilePath detectPython(const FilePath &documentPath) if (defaultInterpreter.exists()) return defaultInterpreter; - const FilePath python3FromPath = env.searchInPath("python3"); - if (python3FromPath.exists()) - return python3FromPath; + auto pythonFromPath = [=](const QString toCheck) { + for (const FilePath &python : env.findAllInPath(toCheck)) { + // Windows creates empty redirector files that may interfere + if (python.exists() && python.osType() == OsTypeWindows && python.fileSize() != 0) + return python; + } + return FilePath(); + }; - const FilePath pythonFromPath = env.searchInPath("python"); - if (pythonFromPath.exists()) - return pythonFromPath; + const FilePath fromPath3 = pythonFromPath("python3"); + if (fromPath3.exists()) + return fromPath3; + + const FilePath fromPath = pythonFromPath("python"); + if (fromPath.exists()) + return fromPath; return PythonSettings::interpreters().value(0).command; } diff --git a/src/plugins/qmakeprojectmanager/externaleditors.cpp b/src/plugins/qmakeprojectmanager/externaleditors.cpp index 3d43bd45418..9d22c2ad0cf 100644 --- a/src/plugins/qmakeprojectmanager/externaleditors.cpp +++ b/src/plugins/qmakeprojectmanager/externaleditors.cpp @@ -170,8 +170,11 @@ bool ExternalQtEditor::getEditorLaunchData(const Utils::FilePath &filePath, qtVersionsToCheck = Utils::filteredUnique(qtVersionsToCheck); // can still contain nullptr data->binary = findFirstCommand(qtVersionsToCheck, m_commandForQtVersion); // fallback - if (data->binary.isEmpty()) - data->binary = Utils::QtcProcess::locateBinary(m_commandForQtVersion(nullptr)); + if (data->binary.isEmpty()) { + const QString path = qEnvironmentVariable("PATH"); + data->binary = Utils::QtcProcess::locateBinary(path, m_commandForQtVersion(nullptr)); + } + if (data->binary.isEmpty()) { *errorMessage = msgAppNotFound(id().toString()); return false; diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 62efb225d44..d6e30746661 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 1db2bc3cb6a..3555bcdefca 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -2035,14 +2035,12 @@ void NodeInstanceView::handleQsbProcessExit(Utils::QtcProcess *qsbProcess, const { --m_remainingQsbTargets; - QString errStr = qsbProcess->errorString(); - QByteArray stdErrStr = qsbProcess->readAllStandardError(); + const QString errStr = qsbProcess->errorString(); + const QByteArray stdErrStr = qsbProcess->readAllStandardError(); if (!errStr.isEmpty() || !stdErrStr.isEmpty()) { - Core::MessageManager::writeSilently( - QCoreApplication::translate("QmlDesigner::NodeInstanceView", - "Failed to generate QSB file for: %1") - .arg(shader)); + Core::MessageManager::writeSilently(QCoreApplication::translate( + "QmlDesigner::NodeInstanceView", "Failed to generate QSB file for: %1").arg(shader)); if (!errStr.isEmpty()) Core::MessageManager::writeSilently(errStr); if (!stdErrStr.isEmpty()) @@ -2137,27 +2135,13 @@ void NodeInstanceView::handleShaderChanges() QStringList args = baseArgs; args.append(outPath.toString()); args.append(shader); - auto qsbProcess = new Utils::QtcProcess; + auto qsbProcess = new Utils::QtcProcess(this); + connect(qsbProcess, &Utils::QtcProcess::done, this, [this, qsbProcess, shader] { + handleQsbProcessExit(qsbProcess, shader); + }); qsbProcess->setWorkingDirectory(srcPath); qsbProcess->setCommand({m_qsbPath, args}); qsbProcess->start(); - - if (!qsbProcess->waitForStarted()) { - handleQsbProcessExit(qsbProcess, shader); - continue; - } - - if (qsbProcess->state() == QProcess::Running) { - connect(qsbProcess, &Utils::QtcProcess::finished, - [thisView = QPointer(this), qsbProcess, shader]() { - if (thisView) - thisView->handleQsbProcessExit(qsbProcess, shader); - else - qsbProcess->deleteLater(); - }); - } else { - handleQsbProcessExit(qsbProcess, shader); - } } } diff --git a/src/plugins/qmldesigner/generateresource.cpp b/src/plugins/qmldesigner/generateresource.cpp index b85370f60f9..9d6be4e1c7c 100644 --- a/src/plugins/qmldesigner/generateresource.cpp +++ b/src/plugins/qmldesigner/generateresource.cpp @@ -217,7 +217,7 @@ void GenerateResource::generateMenuEntry() QTC_ASSERT(currentProject, return); const FilePath projectPath = currentProject->projectFilePath().parentDir(); - auto projectFileName = Core::DocumentManager::getSaveFileName( + auto projectFileName = Core::DocumentManager::getSaveFileNameWithExtension( QCoreApplication::translate("QmlDesigner::GenerateResource", "Save Project as QRC File"), projectPath.pathAppended(currentProject->displayName() + ".qrc"), QCoreApplication::translate("QmlDesigner::GenerateResource", @@ -366,7 +366,7 @@ void GenerateResource::generateMenuEntry() QTC_ASSERT(currentProject, return); const FilePath projectPath = currentProject->projectFilePath().parentDir(); - const FilePath resourceFileName = Core::DocumentManager::getSaveFileName( + const FilePath resourceFileName = Core::DocumentManager::getSaveFileNameWithExtension( QCoreApplication::translate("QmlDesigner::GenerateResource", "Save Project as Resource"), projectPath.pathAppended(currentProject->displayName() + ".qmlrc"), QCoreApplication::translate("QmlDesigner::GenerateResource", diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp index 894e0be8d99..9052ca40f13 100644 --- a/src/plugins/qmljseditor/qmljseditor.cpp +++ b/src/plugins/qmljseditor/qmljseditor.cpp @@ -771,7 +771,8 @@ void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor, const QList imports = semanticInfo.document->bind()->imports(); for (const ImportInfo &import : imports) { if (import.ast() == importAst && import.type() == ImportType::File) { - Utils::Link link(Utils::FilePath::fromString(import.path())); + Utils::Link link( + m_modelManager->fileToSource(FilePath::fromString(import.path()))); link.linkTextStart = importAst->firstSourceLocation().begin(); link.linkTextEnd = importAst->lastSourceLocation().end(); processLinkCallback(Utils::Link()); @@ -793,11 +794,9 @@ void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor, processLinkCallback(link); return; } - const QString relative = QString::fromLatin1("%1/%2").arg( - semanticInfo.document->path(), - text); - if (QFileInfo::exists(relative)) { - link.targetFilePath = Utils::FilePath::fromString(relative); + const Utils::FilePath relative = Utils::FilePath::fromString(semanticInfo.document->path()).pathAppended(text); + if (relative.exists()) { + link.targetFilePath = m_modelManager->fileToSource(relative); processLinkCallback(link); return; } @@ -814,7 +813,7 @@ void QmlJSEditorWidget::findLinkAt(const QTextCursor &cursor, return processLinkCallback(Utils::Link()); Utils::Link link; - link.targetFilePath = Utils::FilePath::fromString(fileName); + link.targetFilePath = m_modelManager->fileToSource(FilePath::fromString(fileName)); link.targetLine = line; link.targetColumn = column - 1; // adjust the column diff --git a/src/plugins/qmljseditor/qmljsfindreferences.cpp b/src/plugins/qmljseditor/qmljsfindreferences.cpp index e0a0f3269aa..38717948ee6 100644 --- a/src/plugins/qmljseditor/qmljsfindreferences.cpp +++ b/src/plugins/qmljseditor/qmljsfindreferences.cpp @@ -28,10 +28,11 @@ #include #include #include -#include #include +#include #include #include +#include #include #include @@ -745,6 +746,7 @@ public: future->waitForResume(); if (future->isCanceled()) return usages; + ModelManagerInterface *modelManager = ModelManagerInterface::instance(); Document::Ptr doc = context->snapshot().document(fileName); if (!doc) return usages; @@ -753,7 +755,7 @@ public: FindUsages findUsages(doc, context); const FindUsages::Result results = findUsages(name, scope); for (const SourceLocation &loc : results) - usages.append(Usage(fileName, matchingLine(loc.offset, doc->source()), loc.startLine, loc.startColumn - 1, loc.length)); + usages.append(Usage(modelManager->fileToSource(Utils::FilePath::fromString(fileName)).toString(), matchingLine(loc.offset, doc->source()), loc.startLine, loc.startColumn - 1, loc.length)); if (future->isPaused()) future->waitForResume(); return usages; @@ -896,8 +898,9 @@ static void find_helper(QFutureInterface &future, QStringList files; for (const Document::Ptr &doc : qAsConst(snapshot)) { // ### skip files that don't contain the name token - files.append(doc->fileName()); + files.append(modelManager->fileToSource(Utils::FilePath::fromString(doc->fileName())).toString()); } + files = Utils::filteredUnique(files); future.setProgressRange(0, files.size()); @@ -976,11 +979,23 @@ QList FindReferences::findUsageOfType(const QString &file QmlJS::Snapshot snapshot = modelManager->snapshot(); + QSet docDone; for (const QmlJS::Document::Ptr &doc : qAsConst(snapshot)) { - FindTypeUsages findUsages(doc, context); + QString sourceFile = modelManager->fileToSource(Utils::FilePath::fromString(doc->fileName())).toString(); + if (docDone.contains(sourceFile)) + continue; + docDone.insert(sourceFile); + QmlJS::Document::Ptr sourceDoc = doc; + if (sourceFile != doc->fileName()) + sourceDoc = snapshot.document(sourceFile); + FindTypeUsages findUsages(sourceDoc, context); const FindTypeUsages::Result results = findUsages(typeName, targetValue); for (const SourceLocation &loc : results) { - usages.append(Usage(doc->fileName(), matchingLine(loc.offset, doc->source()), loc.startLine, loc.startColumn - 1, loc.length)); + usages.append(Usage(sourceFile, + matchingLine(loc.offset, doc->source()), + loc.startLine, + loc.startColumn - 1, + loc.length)); } } return usages; diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp index e46b5cec8e0..1670419a432 100644 --- a/src/plugins/qnx/qnxutils.cpp +++ b/src/plugins/qnx/qnxutils.cpp @@ -125,7 +125,7 @@ EnvironmentItems QnxUtils::qnxEnvironmentFromEnvFile(const FilePath &filePath) return items; // parsing process output - const QString output = process.stdOut(); + const QString output = process.cleanedStdOut(); for (const QString &line : output.split('\n')) { int equalIndex = line.indexOf('='); if (equalIndex < 0) diff --git a/src/plugins/qtsupport/baseqtversion.cpp b/src/plugins/qtsupport/baseqtversion.cpp index 4298c74590e..8b51cdaa6d9 100644 --- a/src/plugins/qtsupport/baseqtversion.cpp +++ b/src/plugins/qtsupport/baseqtversion.cpp @@ -1822,7 +1822,7 @@ static QByteArray runQmakeQuery(const FilePath &binary, const Environment &env, const QByteArray out = process.readAllStandardOutput(); if (out.isEmpty()) { *error = QCoreApplication::translate("QtVersion", "\"%1\" produced no output: %2.") - .arg(binary.displayName(), process.stdErr()); + .arg(binary.displayName(), process.cleanedStdErr()); return {}; } diff --git a/src/plugins/remotelinux/genericdirectuploadservice.cpp b/src/plugins/remotelinux/genericdirectuploadservice.cpp index f4aed62bfd6..6842eb43311 100644 --- a/src/plugins/remotelinux/genericdirectuploadservice.cpp +++ b/src/plugins/remotelinux/genericdirectuploadservice.cpp @@ -146,7 +146,7 @@ QDateTime GenericDirectUploadService::timestampFromStat(const DeployableFile &fi error = tr("\"stat\" crashed."); } else if (statProc->exitCode() != 0) { error = tr("\"stat\" failed with exit code %1: %2") - .arg(statProc->exitCode()).arg(statProc->stdErr()); + .arg(statProc->exitCode()).arg(statProc->cleanedStdErr()); } else { succeeded = true; } diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index edc6a624562..f011d8c563f 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -260,7 +260,7 @@ QString SshSharedConnection::fullProcessError() const { const QString errorString = m_masterProcess->exitStatus() == QProcess::CrashExit ? m_masterProcess->errorString() : QString(); - const QString standardError = m_masterProcess->stdErr(); + const QString standardError = m_masterProcess->cleanedStdErr(); const QString errorPrefix = errorString.isEmpty() && standardError.isEmpty() ? tr("SSH connection failure.") : tr("SSH connection failure:"); QStringList allErrors {errorPrefix, errorString, standardError}; diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 796b9c87d4e..6d0028fb800 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -183,7 +183,7 @@ void GenericLinuxDeviceTester::handleEchoDone() return; } - const QString reply = d->echoProcess.stdOut().chopped(1); // Remove trailing \n + const QString reply = d->echoProcess.cleanedStdOut().chopped(1); // Remove trailing \n if (reply != s_echoContents) emit errorMessage(tr("Device replied to echo with unexpected contents.") + '\n'); else diff --git a/src/plugins/remotelinux/publickeydeploymentdialog.cpp b/src/plugins/remotelinux/publickeydeploymentdialog.cpp index e8c0c3b6ce2..3ba3f011d70 100644 --- a/src/plugins/remotelinux/publickeydeploymentdialog.cpp +++ b/src/plugins/remotelinux/publickeydeploymentdialog.cpp @@ -80,7 +80,7 @@ PublicKeyDeploymentDialog::PublicKeyDeploymentDialog(const IDevice::ConstPtr &de if (!succeeded) { QString errorMessage = d->m_process.errorString(); if (errorMessage.isEmpty()) - errorMessage = d->m_process.stdErr(); + errorMessage = d->m_process.cleanedStdErr(); if (errorMessage.endsWith('\n')) errorMessage.chop(1); finalMessage = tr("Key deployment failed."); diff --git a/src/plugins/remotelinux/rsyncdeploystep.cpp b/src/plugins/remotelinux/rsyncdeploystep.cpp index b4d9929d76b..7b8cf858f19 100644 --- a/src/plugins/remotelinux/rsyncdeploystep.cpp +++ b/src/plugins/remotelinux/rsyncdeploystep.cpp @@ -52,7 +52,7 @@ public: connect(&m_mkdir, &QtcProcess::done, this, [this] { if (m_mkdir.result() != ProcessResult::FinishedWithSuccess) { QString finalMessage = m_mkdir.errorString(); - const QString stdErr = m_mkdir.stdErr(); + const QString stdErr = m_mkdir.cleanedStdErr(); if (!stdErr.isEmpty()) { if (!finalMessage.isEmpty()) finalMessage += '\n'; @@ -140,8 +140,8 @@ void RsyncDeployService::createRemoteDirectories() remoteDirs << file.m_target.parentDir().path(); remoteDirs.sort(); remoteDirs.removeDuplicates(); - m_mkdir.setCommand({deviceConfiguration()->filePath("mkdir"), - {"-p", ProcessArgs::createUnixArgs(remoteDirs).toString()}}); + + m_mkdir.setCommand({deviceConfiguration()->filePath("mkdir"), QStringList("-p") + remoteDirs}); m_mkdir.start(); } diff --git a/src/plugins/remotelinux/tarpackagedeploystep.cpp b/src/plugins/remotelinux/tarpackagedeploystep.cpp index 12add3a4faa..83732a071ba 100644 --- a/src/plugins/remotelinux/tarpackagedeploystep.cpp +++ b/src/plugins/remotelinux/tarpackagedeploystep.cpp @@ -77,7 +77,7 @@ TarPackageInstaller::TarPackageInstaller() connect(&m_installer, &QtcProcess::readyReadStandardError, this, [this] { emit stderrData(QString::fromUtf8(m_installer.readAllStandardError())); }); - connect(&m_installer, &QtcProcess::finished, this, [this] { + connect(&m_installer, &QtcProcess::done, this, [this] { const QString errorMessage = m_installer.result() == ProcessResult::FinishedWithSuccess ? QString() : tr("Installing package failed.") + m_installer.errorString(); emit finished(errorMessage); diff --git a/src/plugins/silversearcher/findinfilessilversearcher.cpp b/src/plugins/silversearcher/findinfilessilversearcher.cpp index d32bbdc22b7..fa9c0a20c29 100644 --- a/src/plugins/silversearcher/findinfilessilversearcher.cpp +++ b/src/plugins/silversearcher/findinfilessilversearcher.cpp @@ -90,7 +90,7 @@ bool isSilverSearcherAvailable() silverSearcherProcess.setCommand({"ag", {"--version"}}); silverSearcherProcess.start(); if (silverSearcherProcess.waitForFinished(1000)) { - if (silverSearcherProcess.stdOut().contains("ag version")) + if (silverSearcherProcess.cleanedStdOut().contains("ag version")) return true; } @@ -145,7 +145,7 @@ void runSilverSeacher(FutureInterfaceType &fi, FileFindParameters parameters) regexp.setPattern(parameters.text); regexp.setPatternOptions(patternOptions); } - SilverSearcher::SilverSearcherOutputParser parser(process.stdOut(), regexp); + SilverSearcher::SilverSearcherOutputParser parser(process.cleanedStdOut(), regexp); FileSearchResultList items = parser.parse(); if (!items.isEmpty()) fi.reportResult(items); diff --git a/src/plugins/subversion/subversionclient.cpp b/src/plugins/subversion/subversionclient.cpp index 3083672d54d..99f13476586 100644 --- a/src/plugins/subversion/subversionclient.cpp +++ b/src/plugins/subversion/subversionclient.cpp @@ -157,7 +157,7 @@ QString SubversionClient::synchronousTopic(const FilePath &repository) const if (proc.result() != ProcessResult::FinishedWithSuccess) return QString(); - return proc.stdOut().trimmed(); + return proc.cleanedStdOut().trimmed(); } QString SubversionClient::escapeFile(const QString &file) diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 97e5ee6649f..46231e4052d 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -1034,8 +1034,8 @@ SubversionResponse SubversionPluginPrivate::runSvn(const FilePath &workingDir, response.error = proc.result() != ProcessResult::FinishedWithSuccess; if (response.error) response.message = proc.exitMessage(); - response.stdErr = proc.stdErr(); - response.stdOut = proc.stdOut(); + response.stdErr = proc.cleanedStdErr(); + response.stdOut = proc.cleanedStdOut(); return response; } diff --git a/src/plugins/texteditor/CMakeLists.txt b/src/plugins/texteditor/CMakeLists.txt index caaa4846b7f..73b52c8bc96 100644 --- a/src/plugins/texteditor/CMakeLists.txt +++ b/src/plugins/texteditor/CMakeLists.txt @@ -13,7 +13,7 @@ add_qtc_plugin(TextEditor basefilefind.cpp basefilefind.h basehoverhandler.cpp basehoverhandler.h behaviorsettings.cpp behaviorsettings.h - behaviorsettingspage.cpp behaviorsettingspage.h behaviorsettingspage.ui + behaviorsettingspage.cpp behaviorsettingspage.h behaviorsettingswidget.cpp behaviorsettingswidget.h behaviorsettingswidget.ui blockrange.h circularclipboard.cpp circularclipboard.h diff --git a/src/plugins/texteditor/behaviorsettingspage.cpp b/src/plugins/texteditor/behaviorsettingspage.cpp index f1c25b45470..d38c2926d36 100644 --- a/src/plugins/texteditor/behaviorsettingspage.cpp +++ b/src/plugins/texteditor/behaviorsettingspage.cpp @@ -26,15 +26,15 @@ #include "behaviorsettingspage.h" #include "behaviorsettings.h" -#include "typingsettings.h" +#include "behaviorsettingswidget.h" +#include "codestylepool.h" +#include "extraencodingsettings.h" +#include "simplecodestylepreferences.h" #include "storagesettings.h" #include "tabsettings.h" -#include "extraencodingsettings.h" -#include "ui_behaviorsettingspage.h" -#include "simplecodestylepreferences.h" #include "texteditorconstants.h" -#include "codestylepool.h" #include "texteditorsettings.h" +#include "typingsettings.h" #include #include @@ -48,8 +48,10 @@ #include #include +#include #include #include +#include namespace TextEditor { @@ -59,7 +61,7 @@ struct BehaviorSettingsPage::BehaviorSettingsPagePrivate : public QObject const QString m_settingsPrefix{"text"}; QPointer m_widget; - Internal::Ui::BehaviorSettingsPage *m_page = nullptr; + TextEditor::BehaviorSettingsWidget *m_behaviorWidget = nullptr; CodeStylePool *m_defaultCodeStylePool = nullptr; SimpleCodeStylePreferences *m_codeStyle = nullptr; @@ -110,17 +112,23 @@ QWidget *BehaviorSettingsPage::widget() { if (!d->m_widget) { d->m_widget = new QWidget; - d->m_page = new Internal::Ui::BehaviorSettingsPage; - d->m_page->setupUi(d->m_widget); + d->m_behaviorWidget = new BehaviorSettingsWidget(d->m_widget); + + auto verticalSpacer = new QSpacerItem(20, 13, QSizePolicy::Minimum, QSizePolicy::Expanding); + + auto gridLayout = new QGridLayout(d->m_widget); if (Utils::HostOsInfo::isMacHost()) - d->m_page->gridLayout->setContentsMargins(-1, 0, -1, 0); // don't ask. + gridLayout->setContentsMargins(-1, 0, -1, 0); // don't ask. + gridLayout->addWidget(d->m_behaviorWidget, 0, 0, 1, 1); + gridLayout->addItem(verticalSpacer, 1, 0, 1, 1); + d->m_pageCodeStyle = new SimpleCodeStylePreferences(d->m_widget); d->m_pageCodeStyle->setDelegatingPool(d->m_codeStyle->delegatingPool()); d->m_pageCodeStyle->setTabSettings(d->m_codeStyle->tabSettings()); d->m_pageCodeStyle->setCurrentDelegate(d->m_codeStyle->currentDelegate()); - d->m_page->behaviorWidget->setCodeStyle(d->m_pageCodeStyle); + d->m_behaviorWidget->setCodeStyle(d->m_pageCodeStyle); - TabSettingsWidget *tabSettingsWidget = d->m_page->behaviorWidget->tabSettingsWidget(); + TabSettingsWidget *tabSettingsWidget = d->m_behaviorWidget->tabSettingsWidget(); tabSettingsWidget->setCodingStyleWarningVisible(true); connect(tabSettingsWidget, &TabSettingsWidget::codingStyleLinkClicked, this, &BehaviorSettingsPage::openCodingStylePreferences); @@ -132,7 +140,7 @@ QWidget *BehaviorSettingsPage::widget() void BehaviorSettingsPage::apply() { - if (!d->m_page) // page was never shown + if (!d->m_behaviorWidget) // page was never shown return; TypingSettings newTypingSettings; @@ -185,9 +193,9 @@ void BehaviorSettingsPage::apply() } s->setValue(QLatin1String(Core::Constants::SETTINGS_DEFAULTTEXTENCODING), - d->m_page->behaviorWidget->assignedCodecName()); + d->m_behaviorWidget->assignedCodecName()); s->setValue(QLatin1String(Core::Constants::SETTINGS_DEFAULT_LINE_TERMINATOR), - d->m_page->behaviorWidget->assignedLineEnding()); + d->m_behaviorWidget->assignedLineEnding()); } void BehaviorSettingsPage::settingsFromUI(TypingSettings *typingSettings, @@ -195,29 +203,25 @@ void BehaviorSettingsPage::settingsFromUI(TypingSettings *typingSettings, BehaviorSettings *behaviorSettings, ExtraEncodingSettings *extraEncodingSettings) const { - d->m_page->behaviorWidget->assignedTypingSettings(typingSettings); - d->m_page->behaviorWidget->assignedStorageSettings(storageSettings); - d->m_page->behaviorWidget->assignedBehaviorSettings(behaviorSettings); - d->m_page->behaviorWidget->assignedExtraEncodingSettings(extraEncodingSettings); + d->m_behaviorWidget->assignedTypingSettings(typingSettings); + d->m_behaviorWidget->assignedStorageSettings(storageSettings); + d->m_behaviorWidget->assignedBehaviorSettings(behaviorSettings); + d->m_behaviorWidget->assignedExtraEncodingSettings(extraEncodingSettings); } void BehaviorSettingsPage::settingsToUI() { - d->m_page->behaviorWidget->setAssignedTypingSettings(d->m_typingSettings); - d->m_page->behaviorWidget->setAssignedStorageSettings(d->m_storageSettings); - d->m_page->behaviorWidget->setAssignedBehaviorSettings(d->m_behaviorSettings); - d->m_page->behaviorWidget->setAssignedExtraEncodingSettings(d->m_extraEncodingSettings); - d->m_page->behaviorWidget->setAssignedCodec(Core::EditorManager::defaultTextCodec()); - d->m_page->behaviorWidget->setAssignedLineEnding(Core::EditorManager::defaultLineEnding()); + d->m_behaviorWidget->setAssignedTypingSettings(d->m_typingSettings); + d->m_behaviorWidget->setAssignedStorageSettings(d->m_storageSettings); + d->m_behaviorWidget->setAssignedBehaviorSettings(d->m_behaviorSettings); + d->m_behaviorWidget->setAssignedExtraEncodingSettings(d->m_extraEncodingSettings); + d->m_behaviorWidget->setAssignedCodec(Core::EditorManager::defaultTextCodec()); + d->m_behaviorWidget->setAssignedLineEnding(Core::EditorManager::defaultLineEnding()); } void BehaviorSettingsPage::finish() { delete d->m_widget; - if (!d->m_page) // page was never shown - return; - delete d->m_page; - d->m_page = nullptr; } ICodeStylePreferences *BehaviorSettingsPage::codeStyle() const diff --git a/src/plugins/texteditor/behaviorsettingspage.ui b/src/plugins/texteditor/behaviorsettingspage.ui deleted file mode 100644 index 44fcf405dc2..00000000000 --- a/src/plugins/texteditor/behaviorsettingspage.ui +++ /dev/null @@ -1,45 +0,0 @@ - - - TextEditor::Internal::BehaviorSettingsPage - - - - 0 - 0 - 432 - 50 - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 13 - - - - - - - - - TextEditor::BehaviorSettingsWidget - QWidget -
texteditor/behaviorsettingswidget.h
- 1 -
-
- - -
diff --git a/src/plugins/texteditor/formattexteditor.cpp b/src/plugins/texteditor/formattexteditor.cpp index 58f48a0bf86..a01f543f1a1 100644 --- a/src/plugins/texteditor/formattexteditor.cpp +++ b/src/plugins/texteditor/formattexteditor.cpp @@ -97,7 +97,7 @@ static FormatTask format(FormatTask task) .arg(process.exitMessage()); return task; } - const QString output = process.stdErr(); + const QString output = process.cleanedStdErr(); if (!output.isEmpty()) task.error = executable + QLatin1String(": ") + output; diff --git a/src/plugins/texteditor/highlightersettings.cpp b/src/plugins/texteditor/highlightersettings.cpp index 7691f39cbed..d4755948084 100644 --- a/src/plugins/texteditor/highlightersettings.cpp +++ b/src/plugins/texteditor/highlightersettings.cpp @@ -71,7 +71,7 @@ FilePath findFallbackDefinitionsLocation() process.setCommand({program, {"--prefix"}}); process.runBlocking(); if (process.result() == ProcessResult::FinishedWithSuccess) { - QString output = process.stdOut(); + QString output = process.cleanedStdOut(); output.remove('\n'); const FilePath dir = FilePath::fromString(output); for (auto &kateSyntaxPath : kateSyntaxPaths) { diff --git a/src/plugins/texteditor/texteditor.qbs b/src/plugins/texteditor/texteditor.qbs index 896c9d515ef..b25d0ea222d 100644 --- a/src/plugins/texteditor/texteditor.qbs +++ b/src/plugins/texteditor/texteditor.qbs @@ -30,7 +30,6 @@ Project { "behaviorsettings.h", "behaviorsettingspage.cpp", "behaviorsettingspage.h", - "behaviorsettingspage.ui", "behaviorsettingswidget.cpp", "behaviorsettingswidget.h", "behaviorsettingswidget.ui", diff --git a/src/plugins/updateinfo/updateinfoplugin.cpp b/src/plugins/updateinfo/updateinfoplugin.cpp index a0617df3a09..78d31e72910 100644 --- a/src/plugins/updateinfo/updateinfoplugin.cpp +++ b/src/plugins/updateinfo/updateinfoplugin.cpp @@ -167,7 +167,7 @@ void UpdateInfoPlugin::startCheckForUpdates() this, [this, futureIf]() mutable { if (d->m_maintenanceToolProcess->result() == ProcessResult::FinishedWithSuccess) { - d->m_updateOutput = d->m_maintenanceToolProcess->stdOut(); + d->m_updateOutput = d->m_maintenanceToolProcess->cleanedStdOut(); if (d->m_settings.checkForQtVersions) { d->m_maintenanceToolProcess.reset(new QtcProcess); d->m_maintenanceToolProcess->setCommand( @@ -181,7 +181,7 @@ void UpdateInfoPlugin::startCheckForUpdates() [this, futureIf]() mutable { if (d->m_maintenanceToolProcess->result() == ProcessResult::FinishedWithSuccess) { - d->m_packagesOutput = d->m_maintenanceToolProcess->stdOut(); + d->m_packagesOutput = d->m_maintenanceToolProcess->cleanedStdOut(); d->m_maintenanceToolProcess.reset(); futureIf.reportFinished(); checkForUpdatesFinished(); diff --git a/src/plugins/valgrind/callgrindengine.cpp b/src/plugins/valgrind/callgrindengine.cpp index aa9b3fad546..974a4848440 100644 --- a/src/plugins/valgrind/callgrindengine.cpp +++ b/src/plugins/valgrind/callgrindengine.cpp @@ -57,17 +57,15 @@ CallgrindToolRunner::CallgrindToolRunner(RunControl *runControl) { setId("CallgrindToolRunner"); - connect(&m_runner, &ValgrindRunner::finished, - this, &CallgrindToolRunner::slotFinished); - connect(&m_parser, &Callgrind::Parser::parserDataReady, - this, &CallgrindToolRunner::slotFinished); - connect(&m_runner, &ValgrindRunner::valgrindStarted, this, [this](qint64 pid) { m_pid = pid; }); - - connect(&m_runner, &ValgrindRunner::extraProcessFinished, this, [this] { + connect(&m_runner, &ValgrindRunner::finished, this, [this] { triggerParse(); + emit parserDataReady(this); + }); + connect(&m_parser, &Callgrind::Parser::parserDataReady, this, [this] { + emit parserDataReady(this); }); m_valgrindRunnable = runControl->runnable(); @@ -152,11 +150,6 @@ Callgrind::ParseData *CallgrindToolRunner::takeParserData() return m_parser.takeData(); } -void CallgrindToolRunner::slotFinished() -{ - emit parserDataReady(this); -} - void CallgrindToolRunner::showStatusMessage(const QString &message) { Debugger::showPermanentStatusMessage(message); @@ -224,7 +217,7 @@ void CallgrindToolRunner::run(Option option) #if CALLGRIND_CONTROL_DEBUG m_controllerProcess->setProcessChannelMode(QProcess::ForwardedChannels); #endif - connect(m_controllerProcess.get(), &QtcProcess::finished, + connect(m_controllerProcess.get(), &QtcProcess::done, this, &CallgrindToolRunner::controllerProcessDone); const FilePath control = diff --git a/src/plugins/valgrind/callgrindengine.h b/src/plugins/valgrind/callgrindengine.h index 21f7abcce0a..1037b234167 100644 --- a/src/plugins/valgrind/callgrindengine.h +++ b/src/plugins/valgrind/callgrindengine.h @@ -77,7 +77,6 @@ signals: void parserDataReady(CallgrindToolRunner *engine); private: - void slotFinished(); void showStatusMessage(const QString &message); /** diff --git a/src/plugins/valgrind/valgrindengine.cpp b/src/plugins/valgrind/valgrindengine.cpp index a6a21e7dcb5..fdb147e1c74 100644 --- a/src/plugins/valgrind/valgrindengine.cpp +++ b/src/plugins/valgrind/valgrindengine.cpp @@ -26,7 +26,6 @@ #include "valgrindengine.h" #include "valgrindsettings.h" -#include "valgrindplugin.h" #include @@ -61,6 +60,17 @@ ValgrindToolRunner::ValgrindToolRunner(RunControl *runControl) setSupportsReRunning(false); m_settings.fromMap(runControl->settingsData(ANALYZER_VALGRIND_SETTINGS)); + + connect(&m_runner, &ValgrindRunner::appendMessage, + this, &ValgrindToolRunner::appendMessage); + connect(&m_runner, &ValgrindRunner::valgrindExecuted, + this, [this](const QString &commandLine) { + appendMessage(commandLine, NormalMessageFormat); + }); + connect(&m_runner, &ValgrindRunner::processErrorReceived, + this, &ValgrindToolRunner::receiveProcessError); + connect(&m_runner, &ValgrindRunner::finished, + this, &ValgrindToolRunner::runnerFinished); } void ValgrindToolRunner::start() @@ -90,23 +100,11 @@ void ValgrindToolRunner::start() valgrind.addArgs(toolArguments()); m_runner.setValgrindCommand(valgrind); - m_runner.setDevice(device()); m_runner.setDebuggee(runControl()->runnable()); if (auto aspect = runControl()->aspect()) m_runner.setUseTerminal(aspect->useTerminal); - connect(&m_runner, &ValgrindRunner::processOutputReceived, - this, &ValgrindToolRunner::receiveProcessOutput); - connect(&m_runner, &ValgrindRunner::valgrindExecuted, - this, [this](const QString &commandLine) { - appendMessage(commandLine, NormalMessageFormat); - }); - connect(&m_runner, &ValgrindRunner::processErrorReceived, - this, &ValgrindToolRunner::receiveProcessError); - connect(&m_runner, &ValgrindRunner::finished, - this, &ValgrindToolRunner::runnerFinished); - if (!m_runner.start()) { m_progress.cancel(); reportFailure(); @@ -161,19 +159,9 @@ void ValgrindToolRunner::runnerFinished() m_progress.reportFinished(); - disconnect(&m_runner, &ValgrindRunner::processOutputReceived, - this, &ValgrindToolRunner::receiveProcessOutput); - disconnect(&m_runner, &ValgrindRunner::finished, - this, &ValgrindToolRunner::runnerFinished); - reportStopped(); } -void ValgrindToolRunner::receiveProcessOutput(const QString &output, OutputFormat format) -{ - appendMessage(output, format); -} - void ValgrindToolRunner::receiveProcessError(const QString &message, QProcess::ProcessError error) { if (error == QProcess::FailedToStart) { diff --git a/src/plugins/valgrind/valgrindengine.h b/src/plugins/valgrind/valgrindengine.h index 06e767b7629..8bb050405af 100644 --- a/src/plugins/valgrind/valgrindengine.h +++ b/src/plugins/valgrind/valgrindengine.h @@ -60,7 +60,6 @@ private: void handleProgressFinished(); void runnerFinished(); - void receiveProcessOutput(const QString &output, Utils::OutputFormat format); void receiveProcessError(const QString &message, QProcess::ProcessError error); QStringList genericToolArguments() const; diff --git a/src/plugins/valgrind/valgrindmemcheckparsertest.cpp b/src/plugins/valgrind/valgrindmemcheckparsertest.cpp index 4ca3d768126..4218f75b211 100644 --- a/src/plugins/valgrind/valgrindmemcheckparsertest.cpp +++ b/src/plugins/valgrind/valgrindmemcheckparsertest.cpp @@ -31,7 +31,6 @@ #include "xmlprotocol/stack.h" #include "xmlprotocol/suppression.h" -#include #include #include @@ -483,8 +482,6 @@ void ValgrindMemcheckParserTest::testParserStop() "-i", dataFile("memcheck-output-sample1.xml"), "--wait", "5" }}); runner.setProcessChannelMode(QProcess::ForwardedChannels); - runner.setDevice(ProjectExplorer::DeviceManager::instance()->defaultDevice( - ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)); runner.start(); QTest::qWait(500); runner.stop(); @@ -505,8 +502,6 @@ void ValgrindMemcheckParserTest::testRealValgrind() ValgrindRunner runner; runner.setValgrindCommand({"valgrind", {}}); runner.setDebuggee(debuggee); - runner.setDevice(ProjectExplorer::DeviceManager::instance()->defaultDevice( - ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)); RunnerDumper dumper(&runner); runner.start(); runner.waitForFinished(); @@ -544,8 +539,6 @@ void ValgrindMemcheckParserTest::testValgrindStartError() ValgrindRunner runner; runner.setValgrindCommand({FilePath::fromString(valgrindExe), valgrindArgs}); runner.setDebuggee(debuggeeExecutable); - runner.setDevice(ProjectExplorer::DeviceManager::instance()->defaultDevice( - ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)); RunnerDumper dumper(&runner); runner.start(); runner.waitForFinished(); diff --git a/src/plugins/valgrind/valgrindrunner.cpp b/src/plugins/valgrind/valgrindrunner.cpp index b547edc802a..f606789cf11 100644 --- a/src/plugins/valgrind/valgrindrunner.cpp +++ b/src/plugins/valgrind/valgrindrunner.cpp @@ -28,7 +28,6 @@ #include "xmlprotocol/threadedparser.h" -#include #include #include #include @@ -45,50 +44,98 @@ namespace Valgrind { class ValgrindRunner::Private : public QObject { public: - Private(ValgrindRunner *owner) : q(owner) {} + Private(ValgrindRunner *owner) : q(owner) { + connect(&m_process, &QtcProcess::started, this, [this] { + emit q->valgrindStarted(m_process.processId()); + }); + connect(&m_process, &QtcProcess::done, this, [this] { + if (m_process.result() != ProcessResult::FinishedWithSuccess) + emit q->processErrorReceived(m_process.errorString(), m_process.error()); + emit q->finished(); + }); + connect(&m_process, &QtcProcess::readyReadStandardOutput, this, [this] { + emit q->appendMessage(QString::fromUtf8(m_process.readAllStandardOutput()), + StdOutFormat); + }); + connect(&m_process, &QtcProcess::readyReadStandardError, this, [this] { + emit q->appendMessage(QString::fromUtf8(m_process.readAllStandardError()), + StdErrFormat); + }); + connect(&m_xmlServer, &QTcpServer::newConnection, this, &Private::xmlSocketConnected); + connect(&m_logServer, &QTcpServer::newConnection, this, &Private::logSocketConnected); + } + + void xmlSocketConnected(); + void logSocketConnected(); + bool startServers(); bool run(); - void processStarted(); - void processDone(); - void localProcessStarted(); - void remoteProcessStarted(); - void findPidProcessDone(); - ValgrindRunner *q; Runnable m_debuggee; - QtcProcess m_valgrindProcess; - IDevice::ConstPtr m_device; - QtcProcess m_findPID; + CommandLine m_command; + QtcProcess m_process; - CommandLine m_valgrindCommand; + QHostAddress m_localServerAddress; - QHostAddress localServerAddress; - QProcess::ProcessChannelMode channelMode = QProcess::SeparateChannels; - - QTcpServer xmlServer; - XmlProtocol::ThreadedParser parser; - QTcpServer logServer; - QTcpSocket *logSocket = nullptr; - - // Workaround for valgrind bug when running vgdb with xml output - // https://bugs.kde.org/show_bug.cgi?id=343902 - bool disableXml = false; + QTcpServer m_xmlServer; + XmlProtocol::ThreadedParser m_parser; + QTcpServer m_logServer; }; +void ValgrindRunner::Private::xmlSocketConnected() +{ + QTcpSocket *socket = m_xmlServer.nextPendingConnection(); + QTC_ASSERT(socket, return); + m_xmlServer.close(); + m_parser.parse(socket); +} + +void ValgrindRunner::Private::logSocketConnected() +{ + QTcpSocket *logSocket = m_logServer.nextPendingConnection(); + QTC_ASSERT(logSocket, return); + connect(logSocket, &QIODevice::readyRead, this, [this, logSocket] { + emit q->logMessageReceived(logSocket->readAll()); + }); + m_logServer.close(); +} + +bool ValgrindRunner::Private::startServers() +{ + const bool xmlOK = m_xmlServer.listen(m_localServerAddress); + const QString ip = m_localServerAddress.toString(); + if (!xmlOK) { + emit q->processErrorReceived(tr("XmlServer on %1:").arg(ip) + ' ' + + m_xmlServer.errorString(), QProcess::FailedToStart ); + return false; + } + m_xmlServer.setMaxPendingConnections(1); + const bool logOK = m_logServer.listen(m_localServerAddress); + if (!logOK) { + emit q->processErrorReceived(tr("LogServer on %1:").arg(ip) + ' ' + + m_logServer.errorString(), QProcess::FailedToStart ); + return false; + } + m_logServer.setMaxPendingConnections(1); + return true; +} + bool ValgrindRunner::Private::run() { CommandLine cmd; - cmd.setExecutable(m_valgrindCommand.executable()); + cmd.setExecutable(m_command.executable()); - if (!localServerAddress.isNull()) { - if (!q->startServers()) + if (!m_localServerAddress.isNull()) { + if (!startServers()) return false; cmd.addArg("--child-silent-after-fork=yes"); - bool enableXml = !disableXml; + // Workaround for valgrind bug when running vgdb with xml output + // https://bugs.kde.org/show_bug.cgi?id=343902 + bool enableXml = true; auto handleSocketParameter = [&enableXml, &cmd](const QString &prefix, const QTcpServer &tcpServer) { @@ -104,32 +151,17 @@ bool ValgrindRunner::Private::run() } }; - handleSocketParameter("--xml-socket", xmlServer); - handleSocketParameter("--log-socket", logServer); + handleSocketParameter("--xml-socket", m_xmlServer); + handleSocketParameter("--log-socket", m_logServer); if (enableXml) cmd.addArg("--xml=yes"); } - cmd.addArgs(m_valgrindCommand.arguments(), CommandLine::Raw); + cmd.addArgs(m_command.arguments(), CommandLine::Raw); - m_valgrindProcess.setProcessChannelMode(channelMode); // consider appending our options last so they override any interfering user-supplied options // -q as suggested by valgrind manual - connect(&m_valgrindProcess, &QtcProcess::started, - this, &ValgrindRunner::Private::processStarted); - connect(&m_valgrindProcess, &QtcProcess::done, - this, &ValgrindRunner::Private::processDone); - - connect(&m_valgrindProcess, &QtcProcess::readyReadStandardOutput, q, [this] { - q->processOutputReceived(QString::fromUtf8(m_valgrindProcess.readAllStandardOutput()), - Utils::StdOutFormat); - }); - connect(&m_valgrindProcess, &QtcProcess::readyReadStandardError, q, [this] { - q->processOutputReceived(QString::fromUtf8(m_valgrindProcess.readAllStandardError()), - Utils::StdErrFormat); - }); - if (cmd.executable().osType() == OsTypeMac) { // May be slower to start but without it we get no filenames for symbols. cmd.addArg("--dsymutil=yes"); @@ -139,92 +171,13 @@ bool ValgrindRunner::Private::run() emit q->valgrindExecuted(cmd.toUserOutput()); - m_valgrindProcess.setCommand(cmd); - m_valgrindProcess.setWorkingDirectory(m_debuggee.workingDirectory); - m_valgrindProcess.setEnvironment(m_debuggee.environment); - m_valgrindProcess.start(); + m_process.setCommand(cmd); + m_process.setWorkingDirectory(m_debuggee.workingDirectory); + m_process.setEnvironment(m_debuggee.environment); + m_process.start(); return true; } -void ValgrindRunner::Private::processStarted() -{ - if (!m_valgrindProcess.commandLine().executable().needsDevice()) - localProcessStarted(); - else - 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(); - emit q->valgrindStarted(pid); -} - -void ValgrindRunner::Private::remoteProcessStarted() -{ - // find out what PID our process has - - // NOTE: valgrind cloaks its name, - // e.g.: valgrind --tool=memcheck foobar - // => ps aux, pidof will see valgrind.bin - // => pkill/killall/top... will see memcheck-amd64-linux or similar - // hence we need to do something more complex... - - // plain path to exe, m_valgrindExe contains e.g. env vars etc. pp. - // FIXME: Really? - const QString proc = m_valgrindCommand.executable().toString().split(' ').last(); - QString procEscaped = proc; - procEscaped.replace("/", "\\\\/"); - - CommandLine cmd(m_device->filePath("/bin/sh"), {}); - // sleep required since otherwise we might only match "bash -c..." and not the actual - // valgrind run - cmd.setArguments(QString("-c \"" - "sleep 1; ps ax" // list all processes with aliased name - " | grep '%1.*%2'" // find valgrind process that runs with our exec - " | awk '\\$5 ~ /^%3/" // 5th column must start with valgrind process - " {print \\$1;}'" // print 1st then (with PID) - "\"").arg(proc, m_debuggee.command.executable().fileName(), procEscaped)); - - m_findPID.setCommand(cmd); - - connect(&m_findPID, &QtcProcess::done, - this, &ValgrindRunner::Private::findPidProcessDone); - - m_findPID.start(); -} - -void ValgrindRunner::Private::findPidProcessDone() -{ - if (m_findPID.result() != ProcessResult::FinishedWithSuccess) { - emit q->processOutputReceived(m_findPID.allOutput(), StdErrFormat); - return; - } - QString out = m_findPID.stdOut(); - if (out.isEmpty()) - return; - bool ok; - const qint64 pid = out.trimmed().toLongLong(&ok); - if (!ok) { -// m_remote.m_errorString = tr("Could not determine remote PID."); -// emit ValgrindRunner::Private::error(QProcess::FailedToStart); -// close(); - } else { - emit q->valgrindStarted(pid); - } -} - ValgrindRunner::ValgrindRunner(QObject *parent) : QObject(parent), d(new Private(this)) { @@ -232,11 +185,11 @@ ValgrindRunner::ValgrindRunner(QObject *parent) ValgrindRunner::~ValgrindRunner() { - if (d->m_valgrindProcess.isRunning()) { + if (d->m_process.isRunning()) { // make sure we don't delete the thread while it's still running waitForFinished(); } - if (d->parser.isRunning()) { + if (d->m_parser.isRunning()) { // make sure we don't delete the thread while it's still running waitForFinished(); } @@ -244,9 +197,9 @@ ValgrindRunner::~ValgrindRunner() d = nullptr; } -void ValgrindRunner::setValgrindCommand(const Utils::CommandLine &command) +void ValgrindRunner::setValgrindCommand(const CommandLine &command) { - d->m_valgrindCommand = command; + d->m_command = command; } void ValgrindRunner::setDebuggee(const Runnable &debuggee) @@ -256,27 +209,22 @@ void ValgrindRunner::setDebuggee(const Runnable &debuggee) void ValgrindRunner::setProcessChannelMode(QProcess::ProcessChannelMode mode) { - d->channelMode = mode; + d->m_process.setProcessChannelMode(mode); } void ValgrindRunner::setLocalServerAddress(const QHostAddress &localServerAddress) { - d->localServerAddress = localServerAddress; -} - -void ValgrindRunner::setDevice(const IDevice::ConstPtr &device) -{ - d->m_device = device; + d->m_localServerAddress = localServerAddress; } void ValgrindRunner::setUseTerminal(bool on) { - d->m_valgrindProcess.setTerminalMode(on ? TerminalMode::On : TerminalMode::Off); + d->m_process.setTerminalMode(on ? TerminalMode::On : TerminalMode::Off); } void ValgrindRunner::waitForFinished() const { - if (d->m_valgrindProcess.state() == QProcess::NotRunning) + if (d->m_process.state() == QProcess::NotRunning) return; QEventLoop loop; @@ -284,6 +232,11 @@ void ValgrindRunner::waitForFinished() const loop.exec(); } +QString ValgrindRunner::errorString() const +{ + return d->m_process.errorString(); +} + bool ValgrindRunner::start() { return d->run(); @@ -291,59 +244,12 @@ bool ValgrindRunner::start() void ValgrindRunner::stop() { - d->m_valgrindProcess.stop(); + d->m_process.stop(); } XmlProtocol::ThreadedParser *ValgrindRunner::parser() const { - return &d->parser; -} - -void ValgrindRunner::xmlSocketConnected() -{ - QTcpSocket *socket = d->xmlServer.nextPendingConnection(); - QTC_ASSERT(socket, return); - d->xmlServer.close(); - d->parser.parse(socket); -} - -void ValgrindRunner::logSocketConnected() -{ - d->logSocket = d->logServer.nextPendingConnection(); - QTC_ASSERT(d->logSocket, return); - connect(d->logSocket, &QIODevice::readyRead, - this, &ValgrindRunner::readLogSocket); - d->logServer.close(); -} - -void ValgrindRunner::readLogSocket() -{ - QTC_ASSERT(d->logSocket, return); - emit logMessageReceived(d->logSocket->readAll()); -} - -bool ValgrindRunner::startServers() -{ - bool check = d->xmlServer.listen(d->localServerAddress); - const QString ip = d->localServerAddress.toString(); - if (!check) { - emit processErrorReceived(tr("XmlServer on %1:").arg(ip) + ' ' - + d->xmlServer.errorString(), QProcess::FailedToStart ); - return false; - } - d->xmlServer.setMaxPendingConnections(1); - connect(&d->xmlServer, &QTcpServer::newConnection, - this, &ValgrindRunner::xmlSocketConnected); - check = d->logServer.listen(d->localServerAddress); - if (!check) { - emit processErrorReceived(tr("LogServer on %1:").arg(ip) + ' ' - + d->logServer.errorString(), QProcess::FailedToStart ); - return false; - } - d->logServer.setMaxPendingConnections(1); - connect(&d->logServer, &QTcpServer::newConnection, - this, &ValgrindRunner::logSocketConnected); - return true; + return &d->m_parser; } } // namespace Valgrind diff --git a/src/plugins/valgrind/valgrindrunner.h b/src/plugins/valgrind/valgrindrunner.h index 3350792b51f..c8701b6e89a 100644 --- a/src/plugins/valgrind/valgrindrunner.h +++ b/src/plugins/valgrind/valgrindrunner.h @@ -52,32 +52,27 @@ public: void setDebuggee(const ProjectExplorer::Runnable &debuggee); void setProcessChannelMode(QProcess::ProcessChannelMode mode); void setLocalServerAddress(const QHostAddress &localServerAddress); - void setDevice(const ProjectExplorer::IDeviceConstPtr &device); void setUseTerminal(bool on); void waitForFinished() const; + QString errorString() const; + bool start(); void stop(); XmlProtocol::ThreadedParser *parser() const; signals: + void appendMessage(const QString &, Utils::OutputFormat); + void logMessageReceived(const QByteArray &); - void processOutputReceived(const QString &, Utils::OutputFormat); void processErrorReceived(const QString &, QProcess::ProcessError); void valgrindExecuted(const QString &); void valgrindStarted(qint64 pid); void finished(); - void extraProcessFinished(); private: - bool startServers(); - - void xmlSocketConnected(); - void logSocketConnected(); - void readLogSocket(); - class Private; Private *d; }; diff --git a/src/plugins/valgrind/valgrindtestrunnertest.cpp b/src/plugins/valgrind/valgrindtestrunnertest.cpp index 4dde3013628..889422b6189 100644 --- a/src/plugins/valgrind/valgrindtestrunnertest.cpp +++ b/src/plugins/valgrind/valgrindtestrunnertest.cpp @@ -91,8 +91,6 @@ QString ValgrindTestRunnerTest::runTestBinary(const QString &binary, const QStri m_runner->setLocalServerAddress(QHostAddress::LocalHost); m_runner->setValgrindCommand(valgrind); m_runner->setDebuggee(debuggee); - m_runner->setDevice(DeviceManager::instance()->defaultDevice( - ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)); m_runner->start(); m_runner->waitForFinished(); return binPath; diff --git a/src/plugins/vcsbase/basevcseditorfactory.cpp b/src/plugins/vcsbase/basevcseditorfactory.cpp index 84414bf76da..e97de8f308e 100644 --- a/src/plugins/vcsbase/basevcseditorfactory.cpp +++ b/src/plugins/vcsbase/basevcseditorfactory.cpp @@ -82,4 +82,6 @@ VcsEditorFactory::VcsEditorFactory(const VcsBaseEditorParameters *parameters, setMarksVisible(false); } +VcsEditorFactory::~VcsEditorFactory() = default; + } // namespace VcsBase diff --git a/src/plugins/vcsbase/basevcseditorfactory.h b/src/plugins/vcsbase/basevcseditorfactory.h index ddd90a93dac..bbc57669784 100644 --- a/src/plugins/vcsbase/basevcseditorfactory.h +++ b/src/plugins/vcsbase/basevcseditorfactory.h @@ -41,6 +41,8 @@ public: VcsEditorFactory(const VcsBaseEditorParameters *parameters, const EditorWidgetCreator editorWidgetCreator, std::function describeFunc); + + ~VcsEditorFactory(); }; } // namespace VcsBase diff --git a/src/plugins/vcsbase/basevcssubmiteditorfactory.cpp b/src/plugins/vcsbase/basevcssubmiteditorfactory.cpp index b285f6453d1..ba6d4fe5c62 100644 --- a/src/plugins/vcsbase/basevcssubmiteditorfactory.cpp +++ b/src/plugins/vcsbase/basevcssubmiteditorfactory.cpp @@ -74,4 +74,6 @@ VcsSubmitEditorFactory::VcsSubmitEditorFactory ActionManager::registerAction(&m_diffAction, DIFF_SELECTED, context); } +VcsSubmitEditorFactory::~VcsSubmitEditorFactory() = default; + } // namespace VcsBase diff --git a/src/plugins/vcsbase/basevcssubmiteditorfactory.h b/src/plugins/vcsbase/basevcssubmiteditorfactory.h index f71d61bbbbf..30e1696d335 100644 --- a/src/plugins/vcsbase/basevcssubmiteditorfactory.h +++ b/src/plugins/vcsbase/basevcssubmiteditorfactory.h @@ -53,6 +53,8 @@ public: const EditorCreator &editorCreator, VcsBasePluginPrivate *plugin); + ~VcsSubmitEditorFactory(); + private: QAction m_submitAction; QAction m_diffAction; diff --git a/src/plugins/vcsbase/vcsbaseclient.cpp b/src/plugins/vcsbase/vcsbaseclient.cpp index 35e61845028..ea43dca0046 100644 --- a/src/plugins/vcsbase/vcsbaseclient.cpp +++ b/src/plugins/vcsbase/vcsbaseclient.cpp @@ -277,7 +277,7 @@ bool VcsBaseClient::synchronousCreateRepository(const FilePath &workingDirectory vcsFullySynchronousExec(proc, workingDirectory, args); if (proc.result() != ProcessResult::FinishedWithSuccess) return false; - VcsOutputWindow::append(proc.stdOut()); + VcsOutputWindow::append(proc.cleanedStdOut()); resetCachedVcsInfo(workingDirectory); diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.cpp b/src/plugins/vcsbase/vcsbaseclientsettings.cpp index 00e20342adf..419e26268f9 100644 --- a/src/plugins/vcsbase/vcsbaseclientsettings.cpp +++ b/src/plugins/vcsbase/vcsbaseclientsettings.cpp @@ -75,6 +75,8 @@ VcsBaseSettings::VcsBaseSettings() timeout.setSuffix(tr("s")); } +VcsBaseSettings::~VcsBaseSettings() = default; + FilePaths VcsBaseSettings::searchPathList() const { return Utils::transform(path.value().split(HostOsInfo::pathListSeparator(), Qt::SkipEmptyParts), diff --git a/src/plugins/vcsbase/vcsbaseclientsettings.h b/src/plugins/vcsbase/vcsbaseclientsettings.h index d6597945038..76091f1d3c5 100644 --- a/src/plugins/vcsbase/vcsbaseclientsettings.h +++ b/src/plugins/vcsbase/vcsbaseclientsettings.h @@ -37,6 +37,7 @@ class VCSBASE_EXPORT VcsBaseSettings : public Utils::AspectContainer public: VcsBaseSettings(); + ~VcsBaseSettings(); Utils::StringAspect binaryPath; Utils::StringAspect userName; diff --git a/src/plugins/webassembly/webassemblyemsdk.cpp b/src/plugins/webassembly/webassemblyemsdk.cpp index c5da7d13570..351bda3062e 100644 --- a/src/plugins/webassembly/webassemblyemsdk.cpp +++ b/src/plugins/webassembly/webassemblyemsdk.cpp @@ -118,7 +118,7 @@ QVersionNumber WebAssemblyEmSdk::version(const FilePath &sdkRoot) emcc.setCommand(command); emcc.setEnvironment(env); emcc.runBlocking(); - const QString version = emcc.stdOut(); + const QString version = emcc.cleanedStdOut(); emSdkVersionCache()->insert(cacheKey, new QVersionNumber(QVersionNumber::fromString(version))); } diff --git a/src/tools/qtcreatorcrashhandler/CMakeLists.txt b/src/tools/qtcreatorcrashhandler/CMakeLists.txt index 74dfd2199f4..64eb7d3d35d 100644 --- a/src/tools/qtcreatorcrashhandler/CMakeLists.txt +++ b/src/tools/qtcreatorcrashhandler/CMakeLists.txt @@ -1,11 +1,10 @@ -if (LINUX) # Debug build only! - add_qtc_executable(qtcreatorcrashhandler - DEPENDS Utils Qt5::Widgets - SOURCES - backtracecollector.cpp backtracecollector.h - crashhandler.cpp crashhandler.h - crashhandlerdialog.cpp crashhandlerdialog.h crashhandlerdialog.ui - main.cpp - utils.cpp utils.h - ) -endif() +add_qtc_executable(qtcreatorcrashhandler + CONDITION UNIX AND NOT APPLE AND (CMAKE_BUILD_TYPE STREQUAL "Debug") + DEPENDS app_version Utils Qt5::Widgets + SOURCES + backtracecollector.cpp backtracecollector.h + crashhandler.cpp crashhandler.h + crashhandlerdialog.cpp crashhandlerdialog.h crashhandlerdialog.ui + main.cpp + utils.cpp utils.h +) diff --git a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp index d5591b787a7..28330786d38 100644 --- a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp +++ b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.cpp @@ -207,7 +207,7 @@ int ProcessTestApp::BlockingProcess::main() return 1; } -int ProcessTestApp::EmitOneErrorOnCrash::main() +int ProcessTestApp::Crash::main() { doCrash(); return 1; diff --git a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h index 4050cb9a2e5..7fbcabc25dc 100644 --- a/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h +++ b/tests/auto/utils/qtcprocess/processtestapp/processtestapp.h @@ -72,7 +72,7 @@ public: SUB_PROCESS(StandardOutputAndErrorWriter); SUB_PROCESS(ChannelForwarding); SUB_PROCESS(BlockingProcess); - SUB_PROCESS(EmitOneErrorOnCrash); + SUB_PROCESS(Crash); SUB_PROCESS(CrashAfterOneSecond); SUB_PROCESS(RecursiveCrashingProcess); SUB_PROCESS(RecursiveBlockingProcess); diff --git a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp index 461da201e5f..c422b690d1f 100644 --- a/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp +++ b/tests/auto/utils/qtcprocess/tst_qtcprocess.cpp @@ -144,7 +144,7 @@ private slots: void destroyBlockingProcess_data(); void destroyBlockingProcess(); void flushFinishedWhileWaitingForReadyRead(); - void emitOneErrorOnCrash(); + void crash(); void crashAfterOneSecond(); void recursiveCrashingProcess(); void recursiveBlockingProcess(); @@ -1012,11 +1012,10 @@ void tst_QtcProcess::notRunningAfterStartingNonExistingProgram() process.setCommand({ FilePath::fromString( "there_is_a_big_chance_that_executable_with_that_name_does_not_exists"), {} }); - int errorCount = 0; - QObject::connect(&process, &QtcProcess::errorOccurred, - [&errorCount](QProcess::ProcessError error) { - ++errorCount; - QCOMPARE(error, QProcess::FailedToStart); + int doneCount = 0; + QObject::connect(&process, &QtcProcess::done, [&process, &doneCount]() { + ++doneCount; + QCOMPARE(process.error(), QProcess::FailedToStart); }); const int loopCount = 2; @@ -1036,6 +1035,7 @@ void tst_QtcProcess::notRunningAfterStartingNonExistingProgram() QVERIFY(process.exitCode() != 0); QCOMPARE(process.result(), ProcessResult::StartFailed); } + QCOMPARE(doneCount, loopCount); } // Since we want to test whether the process forwards its channels or not, we can't just create @@ -1178,23 +1178,22 @@ void tst_QtcProcess::flushFinishedWhileWaitingForReadyRead() QVERIFY(reply.contains(s_simpleTestData)); } -void tst_QtcProcess::emitOneErrorOnCrash() +void tst_QtcProcess::crash() { - SubProcessConfig subConfig(ProcessTestApp::EmitOneErrorOnCrash::envVar(), {}); + SubProcessConfig subConfig(ProcessTestApp::Crash::envVar(), {}); QtcProcess process; subConfig.setupSubProcess(&process); - int errorCount = 0; - connect(&process, &QtcProcess::errorOccurred, this, [&errorCount] { ++errorCount; }); process.start(); QVERIFY(process.waitForStarted(1000)); + QVERIFY(process.isRunning()); QEventLoop loop; - connect(&process, &QtcProcess::finished, &loop, &QEventLoop::quit); + connect(&process, &QtcProcess::done, &loop, &QEventLoop::quit); loop.exec(); - QCOMPARE(errorCount, 1); QCOMPARE(process.error(), QProcess::Crashed); + QCOMPARE(process.exitStatus(), QProcess::CrashExit); } void tst_QtcProcess::crashAfterOneSecond() diff --git a/tests/auto/valgrind/CMakeLists.txt b/tests/auto/valgrind/CMakeLists.txt index 4091dd61268..9a19241b2a0 100644 --- a/tests/auto/valgrind/CMakeLists.txt +++ b/tests/auto/valgrind/CMakeLists.txt @@ -1,2 +1,4 @@ add_subdirectory(callgrind) -# add_subdirectory(memcheck) +if (UNIX) + add_subdirectory(memcheck) +endif() diff --git a/tests/auto/valgrind/callgrind/CMakeLists.txt b/tests/auto/valgrind/callgrind/CMakeLists.txt index 76859938aed..74ed6ef157a 100644 --- a/tests/auto/valgrind/callgrind/CMakeLists.txt +++ b/tests/auto/valgrind/callgrind/CMakeLists.txt @@ -1,3 +1,5 @@ +include(../valgrind.cmake) + add_qtc_test(tst_callgrindparsertests DEPENDS Utils Core ProjectExplorer Debugger Qt5::Core Qt5::Network DEFINES @@ -7,31 +9,6 @@ add_qtc_test(tst_callgrindparsertests SOURCES callgrindparsertests.cpp callgrindparsertests.h ) -extend_qtc_test(tst_callgrindparsertests - SOURCES_PREFIX "${PROJECT_SOURCE_DIR}/src/plugins/valgrind/" - SOURCES - callgrind/callgrindcallmodel.h callgrind/callgrindcallmodel.cpp - callgrind/callgrindcostitem.h callgrind/callgrindcostitem.cpp - callgrind/callgrindcycledetection.h callgrind/callgrindcycledetection.cpp - callgrind/callgrinddatamodel.h callgrind/callgrinddatamodel.cpp - callgrind/callgrindfunction.h callgrind/callgrindfunction_p.h callgrind/callgrindfunction.cpp - callgrind/callgrindfunctioncall.h callgrind/callgrindfunctioncall.cpp - callgrind/callgrindfunctioncycle.h callgrind/callgrindfunctioncycle.cpp - callgrind/callgrindparsedata.h callgrind/callgrindparsedata.cpp - callgrind/callgrindparser.h callgrind/callgrindparser.cpp - callgrind/callgrindproxymodel.h callgrind/callgrindproxymodel.cpp - callgrind/callgrindstackbrowser.h callgrind/callgrindstackbrowser.cpp - valgrindrunner.h valgrindrunner.cpp - xmlprotocol/announcethread.h xmlprotocol/announcethread.cpp - xmlprotocol/error.h xmlprotocol/error.cpp - xmlprotocol/errorlistmodel.h xmlprotocol/errorlistmodel.cpp - xmlprotocol/frame.h xmlprotocol/frame.cpp - xmlprotocol/modelhelpers.h xmlprotocol/modelhelpers.cpp - xmlprotocol/parser.h xmlprotocol/parser.cpp - xmlprotocol/stack.h xmlprotocol/stack.cpp - xmlprotocol/stackmodel.h xmlprotocol/stackmodel.cpp - xmlprotocol/status.h xmlprotocol/status.cpp - xmlprotocol/suppression.h xmlprotocol/suppression.cpp - xmlprotocol/threadedparser.h xmlprotocol/threadedparser.cpp -) +extend_valgrind_test(tst_callgrindparsertests) + # skipping modeltest (does not compile due to missing widget handler) diff --git a/tests/auto/valgrind/memcheck/CMakeLists.txt b/tests/auto/valgrind/memcheck/CMakeLists.txt new file mode 100644 index 00000000000..653611c4d16 --- /dev/null +++ b/tests/auto/valgrind/memcheck/CMakeLists.txt @@ -0,0 +1,27 @@ +add_subdirectory(testapps) + +include(../valgrind.cmake) + +file(RELATIVE_PATH RELATIVE_TEST_PATH "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}") +file(RELATIVE_PATH TEST_RELATIVE_LIBEXEC_PATH "/${RELATIVE_TEST_PATH}" "/${IDE_LIBEXEC_PATH}") + +add_qtc_test(modeldemo + MANUALTEST + DEPENDS + Utils + Core + Debugger + ProjectExplorer + TextEditor + + SOURCES + modeldemo.cpp + modeldemo.h + + DEFINES + PARSERTESTS_DATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data" + VALGRIND_FAKE_PATH="${PROJECT_BINARY_DIR}/src/tools/valgrindfake/valgrind-fake" + TEST_RELATIVE_LIBEXEC_PATH="${TEST_RELATIVE_LIBEXEC_PATH}" +) + +extend_valgrind_test(modeldemo) diff --git a/tests/auto/valgrind/memcheck/modeldemo.cpp b/tests/auto/valgrind/memcheck/modeldemo.cpp index 9f809161da9..996ddf1af04 100644 --- a/tests/auto/valgrind/memcheck/modeldemo.cpp +++ b/tests/auto/valgrind/memcheck/modeldemo.cpp @@ -24,6 +24,9 @@ ** ****************************************************************************/ +#include +#include + #include #include #include @@ -41,12 +44,17 @@ using namespace Valgrind::XmlProtocol; int main(int argc, char *argv[]) { QApplication app(argc, argv); + + Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/QtCreator-XXXXXX"); + const QString libExecPath(qApp->applicationDirPath() + '/' + + QLatin1String(TEST_RELATIVE_LIBEXEC_PATH)); + Utils::LauncherInterface::setPathToLauncher(libExecPath); + qRegisterMetaType(); ValgrindRunner runner; runner.setValgrindCommand({VALGRIND_FAKE_PATH, {"-i", PARSERTESTS_DATA_DIR "/memcheck-output-sample1.xml"}}); - ModelDemo demo(&runner); QObject::connect(&runner, &ValgrindRunner::finished, &demo, &ModelDemo::finished); diff --git a/tests/auto/valgrind/memcheck/modeldemo.qbs b/tests/auto/valgrind/memcheck/modeldemo.qbs index 8da8fd139e8..7da91345ee7 100644 --- a/tests/auto/valgrind/memcheck/modeldemo.qbs +++ b/tests/auto/valgrind/memcheck/modeldemo.qbs @@ -1,4 +1,5 @@ import qbs +import qbs.FileInfo import "../valgrindautotest.qbs" as ValgrindAutotest ValgrindAutotest { @@ -6,8 +7,14 @@ ValgrindAutotest { Depends { name: "valgrind-fake" } Depends { name: "Qt.network" } files: ["modeldemo.h", "modeldemo.cpp"] - cpp.defines: base.concat([ - 'PARSERTESTS_DATA_DIR="' + path + '/data"', - 'VALGRIND_FAKE_PATH="' + project.buildDirectory + '/' + qtc.ide_bin_path + '/valgrind-fake"' - ]) + cpp.defines: { + var defines = base; + var absLibExecPath = FileInfo.joinPaths(qbs.installRoot, qbs.installPrefix, + qtc.ide_libexec_path); + var relLibExecPath = FileInfo.relativePath(destinationDirectory, absLibExecPath); + defines.push('TEST_RELATIVE_LIBEXEC_PATH="' + relLibExecPath + '"'); + defines.push('PARSERTESTS_DATA_DIR="' + path + '/data"'); + defines.push('VALGRIND_FAKE_PATH="' + project.buildDirectory + '/' + qtc.ide_bin_path + '/valgrind-fake"'); + return defines; + } } diff --git a/tests/auto/valgrind/memcheck/testapps/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/CMakeLists.txt new file mode 100644 index 00000000000..89149fc5309 --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/CMakeLists.txt @@ -0,0 +1,12 @@ +add_subdirectory(free1) +add_subdirectory(free2) +add_subdirectory(invalidjump) +add_subdirectory(leak1) +add_subdirectory(leak2) +add_subdirectory(leak3) +add_subdirectory(leak4) +add_subdirectory(overlap) +add_subdirectory(syscall) +add_subdirectory(uninit1) +add_subdirectory(uninit2) +add_subdirectory(uninit3) diff --git a/tests/auto/valgrind/memcheck/testapps/free1/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/free1/CMakeLists.txt new file mode 100644 index 00000000000..99ca11c06c2 --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/free1/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(free1) diff --git a/tests/auto/valgrind/memcheck/testapps/free2/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/free2/CMakeLists.txt new file mode 100644 index 00000000000..798be2b8122 --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/free2/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(free2) diff --git a/tests/auto/valgrind/memcheck/testapps/invalidjump/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/invalidjump/CMakeLists.txt new file mode 100644 index 00000000000..17ab08a4e44 --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/invalidjump/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(invalidjump) diff --git a/tests/auto/valgrind/memcheck/testapps/leak1/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/leak1/CMakeLists.txt new file mode 100644 index 00000000000..cd05f350fda --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/leak1/CMakeLists.txt @@ -0,0 +1,5 @@ +include(../testapp.cmake) + +add_valgrind_testapp(leak1) +target_link_libraries(leak1 PRIVATE Qt5::Core) + diff --git a/tests/auto/valgrind/memcheck/testapps/leak2/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/leak2/CMakeLists.txt new file mode 100644 index 00000000000..a1134baf9c9 --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/leak2/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(leak2) diff --git a/tests/auto/valgrind/memcheck/testapps/leak3/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/leak3/CMakeLists.txt new file mode 100644 index 00000000000..d825d1ac82d --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/leak3/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(leak3) diff --git a/tests/auto/valgrind/memcheck/testapps/leak4/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/leak4/CMakeLists.txt new file mode 100644 index 00000000000..112d8b2e9df --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/leak4/CMakeLists.txt @@ -0,0 +1,4 @@ +include(../testapp.cmake) + +add_valgrind_testapp(leak4) +target_link_libraries(leak4 PRIVATE Qt5::Core) diff --git a/tests/auto/valgrind/memcheck/testapps/overlap/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/overlap/CMakeLists.txt new file mode 100644 index 00000000000..149f26e3bdf --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/overlap/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(overlap) diff --git a/tests/auto/valgrind/memcheck/testapps/syscall/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/syscall/CMakeLists.txt new file mode 100644 index 00000000000..639996072b3 --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/syscall/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(syscall) diff --git a/tests/auto/valgrind/memcheck/testapps/testapp.cmake b/tests/auto/valgrind/memcheck/testapps/testapp.cmake new file mode 100644 index 00000000000..25d8a154b7e --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/testapp.cmake @@ -0,0 +1,4 @@ +function(add_valgrind_testapp name) + add_executable("${name}" + ${CMAKE_CURRENT_LIST_DIR}/main.cpp) +endfunction() diff --git a/tests/auto/valgrind/memcheck/testapps/uninit1/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/uninit1/CMakeLists.txt new file mode 100644 index 00000000000..99296862d5f --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/uninit1/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(uninit1) diff --git a/tests/auto/valgrind/memcheck/testapps/uninit2/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/uninit2/CMakeLists.txt new file mode 100644 index 00000000000..32f279703cc --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/uninit2/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(uninit2) diff --git a/tests/auto/valgrind/memcheck/testapps/uninit3/CMakeLists.txt b/tests/auto/valgrind/memcheck/testapps/uninit3/CMakeLists.txt new file mode 100644 index 00000000000..def23876926 --- /dev/null +++ b/tests/auto/valgrind/memcheck/testapps/uninit3/CMakeLists.txt @@ -0,0 +1,3 @@ +include(../testapp.cmake) + +add_valgrind_testapp(uninit3) diff --git a/tests/auto/valgrind/valgrind.cmake b/tests/auto/valgrind/valgrind.cmake new file mode 100644 index 00000000000..fa7d8b4b60b --- /dev/null +++ b/tests/auto/valgrind/valgrind.cmake @@ -0,0 +1,30 @@ + +function(extend_valgrind_test targetName) + extend_qtc_test(${targetName} + SOURCES_PREFIX "${PROJECT_SOURCE_DIR}/src/plugins/valgrind/" + SOURCES + callgrind/callgrindcallmodel.h callgrind/callgrindcallmodel.cpp + callgrind/callgrindcostitem.h callgrind/callgrindcostitem.cpp + callgrind/callgrindcycledetection.h callgrind/callgrindcycledetection.cpp + callgrind/callgrinddatamodel.h callgrind/callgrinddatamodel.cpp + callgrind/callgrindfunction.h callgrind/callgrindfunction_p.h callgrind/callgrindfunction.cpp + callgrind/callgrindfunctioncall.h callgrind/callgrindfunctioncall.cpp + callgrind/callgrindfunctioncycle.h callgrind/callgrindfunctioncycle.cpp + callgrind/callgrindparsedata.h callgrind/callgrindparsedata.cpp + callgrind/callgrindparser.h callgrind/callgrindparser.cpp + callgrind/callgrindproxymodel.h callgrind/callgrindproxymodel.cpp + callgrind/callgrindstackbrowser.h callgrind/callgrindstackbrowser.cpp + valgrindrunner.h valgrindrunner.cpp + xmlprotocol/announcethread.h xmlprotocol/announcethread.cpp + xmlprotocol/error.h xmlprotocol/error.cpp + xmlprotocol/errorlistmodel.h xmlprotocol/errorlistmodel.cpp + xmlprotocol/frame.h xmlprotocol/frame.cpp + xmlprotocol/modelhelpers.h xmlprotocol/modelhelpers.cpp + xmlprotocol/parser.h xmlprotocol/parser.cpp + xmlprotocol/stack.h xmlprotocol/stack.cpp + xmlprotocol/stackmodel.h xmlprotocol/stackmodel.cpp + xmlprotocol/status.h xmlprotocol/status.cpp + xmlprotocol/suppression.h xmlprotocol/suppression.cpp + xmlprotocol/threadedparser.h xmlprotocol/threadedparser.cpp + ) +endfunction() diff --git a/tests/manual/debugger/gui/CMakeLists.txt b/tests/manual/debugger/gui/CMakeLists.txt index 59e45b3804d..21c89f291cb 100644 --- a/tests/manual/debugger/gui/CMakeLists.txt +++ b/tests/manual/debugger/gui/CMakeLists.txt @@ -16,3 +16,10 @@ add_executable(manual_test_debugger_gui tst_gui.cpp ) target_link_libraries(manual_test_debugger_gui PRIVATE Qt${QT_VERSION_MAJOR}::Widgets) + +if (NOT QT_CREATOR_API_DEFINED) + if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set (CMAKE_INSTALL_PREFIX "/tmp/manual_test_debugger_gui" CACHE PATH "default install path" FORCE) + endif() + install(TARGETS manual_test_debugger_gui) + endif() diff --git a/tests/manual/debugger/gui/gui.qbs b/tests/manual/debugger/gui/gui.qbs index 7a464f77c17..88e9bd53071 100644 --- a/tests/manual/debugger/gui/gui.qbs +++ b/tests/manual/debugger/gui/gui.qbs @@ -1,5 +1,6 @@ QtApplication { name: "Manual debugger gui test" + Depends { name: "qtc" } Depends { name: "Qt.widgets" } files: [ diff --git a/tests/manual/debugger/simple/simple_test_app.qbs b/tests/manual/debugger/simple/simple_test_app.qbs index 59cf3fe3074..ca2c56229e4 100644 --- a/tests/manual/debugger/simple/simple_test_app.qbs +++ b/tests/manual/debugger/simple/simple_test_app.qbs @@ -5,6 +5,7 @@ CppApplication { name: "Manual Test Simple Application" targetName: "simple_test_app" + Depends { name: "qtc" } Depends { name: "Qt.core" } Depends { name: "Qt.core-private"; required: false; condition: Qt.core.versionMajor > 4 } Depends { name: "Qt.core5compat"; condition: Qt.core.versionMajor > 5 } diff --git a/tests/manual/debugger/simple/simple_test_plugin.qbs b/tests/manual/debugger/simple/simple_test_plugin.qbs index 33f257c449b..eca6791c02c 100644 --- a/tests/manual/debugger/simple/simple_test_plugin.qbs +++ b/tests/manual/debugger/simple/simple_test_plugin.qbs @@ -4,6 +4,7 @@ DynamicLibrary { name: "Manual Test Simple Plugin" targetName: "simple_test_plugin" + Depends { name: "qtc" } Depends { name: "Qt.core" } files: [ "simple_test_plugin.cpp" ] diff --git a/tests/manual/widgets/crumblepath/crumblepath.qbs b/tests/manual/widgets/crumblepath/crumblepath.qbs index af1860a52ec..c9b32a0810f 100644 --- a/tests/manual/widgets/crumblepath/crumblepath.qbs +++ b/tests/manual/widgets/crumblepath/crumblepath.qbs @@ -3,6 +3,7 @@ import "../common/common.qbs" as Common CppApplication { name: "Manual Test Utils CrumblePath" + Depends { name: "qtc" } Depends { name: "Core" } Depends { name: "Utils" } diff --git a/tests/manual/widgets/infolabel/infolabel.qbs b/tests/manual/widgets/infolabel/infolabel.qbs index ce00065c7cf..dfba3bd9ef7 100644 --- a/tests/manual/widgets/infolabel/infolabel.qbs +++ b/tests/manual/widgets/infolabel/infolabel.qbs @@ -3,6 +3,7 @@ import "../common/common.qbs" as Common CppApplication { name: "Manual Test Utils InfoLabel" + Depends { name: "qtc" } Depends { name: "Core" } Depends { name: "Utils" } diff --git a/tests/manual/widgets/manhattanstyle/manhattanstyle.qbs b/tests/manual/widgets/manhattanstyle/manhattanstyle.qbs index 97a728a6f63..c04bd03e89f 100644 --- a/tests/manual/widgets/manhattanstyle/manhattanstyle.qbs +++ b/tests/manual/widgets/manhattanstyle/manhattanstyle.qbs @@ -3,6 +3,7 @@ import "../common/common.qbs" as Common CppApplication { name: "Manual Test Utils ManhattanStyle" + Depends { name: "qtc" } Depends { name: "Core" } Depends { name: "Utils" } diff --git a/tests/manual/widgets/tracing/tracing.qbs b/tests/manual/widgets/tracing/tracing.qbs index 06bbc4edd4a..95e661910ce 100644 --- a/tests/manual/widgets/tracing/tracing.qbs +++ b/tests/manual/widgets/tracing/tracing.qbs @@ -3,6 +3,7 @@ import "../common/common.qbs" as Common CppApplication { name: "Manual Test Tracing" + Depends { name: "qtc" } Depends { name: "Qt.quick" } Depends { name: "Tracing" } Depends { name: "Utils" }