Merge remote-tracking branch 'origin/8.0'

Change-Id: I3f218b52bf6904daca3779fb677e51f6f51f2f9f
This commit is contained in:
Eike Ziller
2022-06-23 11:17:33 +02:00
239 changed files with 2001 additions and 1532 deletions

View File

@@ -7,7 +7,7 @@ on:
- 'doc/**' - 'doc/**'
env: env:
QT_VERSION: 6.3.0 QT_VERSION: 6.3.1
CLANG_VERSION: 14.0.3 CLANG_VERSION: 14.0.3
ELFUTILS_VERSION: 0.175 ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.21.1 CMAKE_VERSION: 3.21.1

View File

@@ -1,6 +1,6 @@
set(IDE_VERSION "7.82.0") # The IDE version. set(IDE_VERSION "7.83.0") # The IDE version.
set(IDE_VERSION_COMPAT "7.82.0") # The IDE Compatibility version. set(IDE_VERSION_COMPAT "7.83.0") # The IDE Compatibility version.
set(IDE_VERSION_DISPLAY "8.0.0-beta1") # The IDE display 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_COPYRIGHT_YEAR "2022") # The IDE current copyright year.
set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation. set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.

View File

@@ -13,7 +13,7 @@ instructions:
instructions: instructions:
- type: EnvironmentVariable - type: EnvironmentVariable
variableName: QTC_QT_BASE_URL 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 - type: EnvironmentVariable
variableName: QTC_QT_MODULES variableName: QTC_QT_MODULES
variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations" variableValue: "qt5compat qtbase qtdeclarative qtimageformats qtquick3d qtquickcontrols2 qtquicktimeline qtserialport qtshadertools qtsvg qttools qttranslations"

View File

@@ -31,6 +31,15 @@ instructions:
condition: property condition: property
property: host.os property: host.os
in_values: [MacOS, Linux, Windows] 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 - 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}}" 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 executeCommandArgumentSplitingBehavior: SplitAfterVariableSubstitution
@@ -52,10 +61,10 @@ instructions:
property: host.os property: host.os
equals_value: MacOS equals_value: MacOS
- type: ExecuteCommand - type: ExecuteCommand
command: "pip.exe install pywin32" command: "pip.exe install pywin32 wget colorlog"
maxTimeInSeconds: 1200 maxTimeInSeconds: 1200
maxTimeBetweenOutput: 120 maxTimeBetweenOutput: 120
userMessageOnFailure: "Failed to install win32api, check logs." userMessageOnFailure: "Failed to install Python packages, check logs."
enable_if: enable_if:
condition: property condition: property
property: host.os property: host.os

View File

@@ -1,17 +1,20 @@
import qbs import qbs
import qbs.Environment import qbs.Environment
import qbs.FileInfo import qbs.FileInfo
import qbs.Utilities
Module { 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_major: '7'
property string ide_version_minor: '82' property string ide_version_minor: '83'
property string ide_version_release: '0' property string ide_version_release: '0'
property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.' property string qtcreator_version: ide_version_major + '.' + ide_version_minor + '.'
+ ide_version_release + ide_version_release
property string ide_compat_version_major: '7' 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 ide_compat_version_release: '0'
property string qtcreator_compat_version: ide_compat_version_major + '.' property string qtcreator_compat_version: ide_compat_version_major + '.'
+ ide_compat_version_minor + '.' + ide_compat_version_release + ide_compat_version_minor + '.' + ide_compat_version_release
@@ -92,4 +95,12 @@ Module {
"QT_USE_QSTRINGBUILDER", "QT_USE_QSTRINGBUILDER",
].concat(testsEnabled ? ["WITH_TESTS"] : []) ].concat(testsEnabled ? ["WITH_TESTS"] : [])
.concat(qbs.toolchain.contains("msvc") ? ["_CRT_SECURE_NO_WARNINGS"] : []) .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-"
}
} }

View File

@@ -1,6 +1,6 @@
QTCREATOR_VERSION = 7.82.0 QTCREATOR_VERSION = 7.83.0
QTCREATOR_COMPAT_VERSION = 7.82.0 QTCREATOR_COMPAT_VERSION = 7.83.0
QTCREATOR_DISPLAY_VERSION = 8.0.0-beta1 QTCREATOR_DISPLAY_VERSION = 8.0.0-beta2
QTCREATOR_COPYRIGHT_YEAR = 2022 QTCREATOR_COPYRIGHT_YEAR = 2022
IDE_DISPLAY_NAME = Qt Creator IDE_DISPLAY_NAME = Qt Creator

View File

@@ -238,7 +238,7 @@ def deploy_clang(install_dir, llvm_install_dir, chrpath_bin):
clanglibdirtarget = os.path.join(install_dir, 'bin', 'clang', 'lib') clanglibdirtarget = os.path.join(install_dir, 'bin', 'clang', 'lib')
if not os.path.exists(clanglibdirtarget): if not os.path.exists(clanglibdirtarget):
os.makedirs(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') binary_filepath = os.path.join(llvm_install_dir, 'bin', binary + '.exe')
if os.path.exists(binary_filepath): if os.path.exists(binary_filepath):
deployinfo.append((binary_filepath, clangbindirtarget)) 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') clangbinary_targetdir = os.path.join(install_dir, 'libexec', 'qtcreator', 'clang', 'bin')
if not os.path.exists(clangbinary_targetdir): if not os.path.exists(clangbinary_targetdir):
os.makedirs(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) binary_filepath = os.path.join(llvm_install_dir, 'bin', binary)
if os.path.exists(binary_filepath): if os.path.exists(binary_filepath):
deployinfo.append((binary_filepath, clangbinary_targetdir)) 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): if not os.path.exists(clanglibs_targetdir):
os.makedirs(clanglibs_targetdir) os.makedirs(clanglibs_targetdir)
# on RHEL ClazyPlugin is in lib64 # 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)): for lib in glob(os.path.join(llvm_install_dir, lib_pattern)):
deployinfo.append((lib, clanglibs_targetdir)) deployinfo.append((lib, clanglibs_targetdir))
resourcetarget = os.path.join(install_dir, 'libexec', 'qtcreator', 'clang', 'lib', 'clang') resourcetarget = os.path.join(install_dir, 'libexec', 'qtcreator', 'clang', 'lib', 'clang')

View File

@@ -111,21 +111,14 @@ fi
# copy clang if needed # copy clang if needed
if [ $LLVM_INSTALL_DIR ]; then 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" echo "- Copying clang"
mkdir -p "$app_path/Contents/Frameworks" || exit 1 mkdir -p "$app_path/Contents/Frameworks" || exit 1
# use recursive copy to make it copy symlinks as symlinks # use recursive copy to make it copy symlinks as symlinks
mkdir -p "$libexec_path/clang/bin" mkdir -p "$libexec_path/clang/bin"
mkdir -p "$libexec_path/clang/lib" 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/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 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 clangdsource="$LLVM_INSTALL_DIR"/bin/clangd
cp -Rf "$clangdsource" "$libexec_path/clang/bin/" || exit 1 cp -Rf "$clangdsource" "$libexec_path/clang/bin/" || exit 1
clangtidysource="$LLVM_INSTALL_DIR"/bin/clang-tidy clangtidysource="$LLVM_INSTALL_DIR"/bin/clang-tidy

View File

@@ -29,7 +29,6 @@ import collections
import glob import glob
import struct import struct
import sys import sys
import base64
import re import re
import time import time
import inspect import inspect
@@ -45,6 +44,14 @@ except:
"Native combined debugging might not work.") "Native combined debugging might not work.")
pass 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: if sys.version_info[0] >= 3:
toInteger = int toInteger = int
@@ -550,7 +557,7 @@ class DumperBase():
return s.encode('hex') return s.encode('hex')
if isinstance(s, str): if isinstance(s, str):
s = s.encode('utf8') s = s.encode('utf8')
return base64.b16encode(s).decode('utf8') return hexencode_(s)
def isQt3Support(self): def isQt3Support(self):
# assume no Qt 3 support by default # assume no Qt 3 support by default

View File

@@ -33,7 +33,11 @@
"name": "PySideVersion", "name": "PySideVersion",
"trDisplayName": "PySide version:", "trDisplayName": "PySide version:",
"type": "ComboBox", "type": "ComboBox",
"data": { "items": [ "PySide2", "PySide6" ] } "data":
{
"index": 1,
"items": [ "PySide2", "PySide6" ]
}
} }
] ]
}, },

View File

@@ -34,7 +34,11 @@
"name": "PySideVersion", "name": "PySideVersion",
"trDisplayName": "PySide version:", "trDisplayName": "PySide version:",
"type": "ComboBox", "type": "ComboBox",
"data": { "items": [ "PySide2", "PySide6" ] } "data":
{
"index": 1,
"items": [ "PySide2", "PySide6" ]
}
}, },
{ {
"name": "Class", "name": "Class",

View File

@@ -39,7 +39,7 @@
"type": "ComboBox", "type": "ComboBox",
"data": "data":
{ {
"index": 2, "index": 0,
"items": "items":
[ [
{ {

View File

@@ -34,7 +34,11 @@
"name": "PySideVersion", "name": "PySideVersion",
"trDisplayName": "PySide version:", "trDisplayName": "PySide version:",
"type": "ComboBox", "type": "ComboBox",
"data": { "items": [ "PySide2", "PySide6" ] } "data":
{
"index": 1,
"items": [ "PySide2", "PySide6" ]
}
}, },
{ {
"name": "Class", "name": "Class",

View File

@@ -34,7 +34,11 @@
"name": "PySideVersion", "name": "PySideVersion",
"trDisplayName": "PySide version:", "trDisplayName": "PySide version:",
"type": "ComboBox", "type": "ComboBox",
"data": { "items": [ "PySide2", "PySide6" ] } "data":
{
"index": 1,
"items": [ "PySide2", "PySide6" ]
}
}, },
{ {
"name": "Class", "name": "Class",

View File

@@ -49,6 +49,16 @@ Utils::optional<CompletionItem::InsertTextFormat> CompletionItem::insertTextForm
return Utils::nullopt; return Utils::nullopt;
} }
Utils::optional<QList<CompletionItem::CompletionItemTag>> CompletionItem::tags() const
{
if (const auto value = optionalValue<QJsonArray>(tagsKey)) {
QList<CompletionItemTag> tags;
for (auto it = value->cbegin(); it != value->cend(); ++it)
tags << static_cast<CompletionItemTag>(it->toInt());
return tags;
}
return {};
}
CompletionItemResolveRequest::CompletionItemResolveRequest(const CompletionItem &params) CompletionItemResolveRequest::CompletionItemResolveRequest(const CompletionItem &params)
: Request(methodName, params) : Request(methodName, params)

View File

@@ -214,6 +214,27 @@ public:
void setData(const QJsonValue &data) { insert(dataKey, data); } void setData(const QJsonValue &data) { insert(dataKey, data); }
void clearData() { remove(dataKey); } 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<QList<CompletionItemTag>> tags() const;
/**
* Indicates if this item is deprecated.
* @deprecated Use `tags` instead if supported.
*/
Utils::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); }
bool isValid() const override { return contains(labelKey); } bool isValid() const override { return contains(labelKey); }
}; };

View File

@@ -209,6 +209,7 @@ constexpr char symbolKindKey[] = "symbolKind";
constexpr char syncKindKey[] = "syncKind"; constexpr char syncKindKey[] = "syncKind";
constexpr char synchronizationKey[] = "synchronization"; constexpr char synchronizationKey[] = "synchronization";
constexpr char tabSizeKey[] = "tabSize"; constexpr char tabSizeKey[] = "tabSize";
constexpr char tagsKey[] = "tags";
constexpr char targetKey[] = "target"; constexpr char targetKey[] = "target";
constexpr char textDocumentKey[] = "textDocument"; constexpr char textDocumentKey[] = "textDocument";
constexpr char textDocumentSyncKey[] = "textDocumentSync"; constexpr char textDocumentSyncKey[] = "textDocumentSync";

View File

@@ -334,7 +334,7 @@ protected:
_doc->fileName(), _doc->fileName(),
line, column, line, column,
QmlJS::FindExportedCppTypes::tr( 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" "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.")); "the QML editor know about a likely URI."));
} }

View File

@@ -2378,8 +2378,12 @@ const Value *TypeScope::lookupMember(const QString &name, const Context *context
continue; continue;
if (const Value *v = import->lookupMember(name, context, foundInObject)) { if (const Value *v = import->lookupMember(name, context, foundInObject)) {
i.used = true; // FIXME if we have multiple non-aliased imports containing this object we'd have to
return v; // disambiguate (and inform the user) about this issue
if (info.as().isEmpty()) {
i.used = true;
return v;
}
} }
} }
if (foundInObject) if (foundInObject)

View File

@@ -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 " "For Qbs projects, declare and set a qmlImportPaths property in your product "
"to add import paths.\n" "to add import paths.\n"
"For qmlproject projects, use the importPaths property 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')))); .arg(importInfo.name(), m_importPaths.join(QLatin1Char('\n'))));
} }

View File

@@ -446,6 +446,20 @@ bool pInfoLessThanImports(const ModelManagerInterface::ProjectInfo &p1,
} }
static QList<Utils::FilePath> generatedQrc(QStringList applicationDirectories)
{
QList<Utils::FilePath> 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( void ModelManagerInterface::iterateQrcFiles(
ProjectExplorer::Project *project, QrcResourceSelector resources, ProjectExplorer::Project *project, QrcResourceSelector resources,
const std::function<void(QrcParser::ConstPtr)> &callback) const std::function<void(QrcParser::ConstPtr)> &callback)
@@ -461,18 +475,21 @@ void ModelManagerInterface::iterateQrcFiles(
Utils::sort(pInfos, &pInfoLessThanAll); Utils::sort(pInfos, &pInfoLessThanAll);
} }
QSet<QString> pathsChecked; QSet<Utils::FilePath> pathsChecked;
for (const ModelManagerInterface::ProjectInfo &pInfo : qAsConst(pInfos)) { for (const ModelManagerInterface::ProjectInfo &pInfo : qAsConst(pInfos)) {
QStringList qrcFilePaths; QStringList qrcFilePaths;
if (resources == ActiveQrcResources) if (resources == ActiveQrcResources)
qrcFilePaths = pInfo.activeResourceFiles; qrcFilePaths = pInfo.activeResourceFiles;
else else
qrcFilePaths = pInfo.allResourceFiles; 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)) if (pathsChecked.contains(qrcFilePath))
continue; continue;
pathsChecked.insert(qrcFilePath); pathsChecked.insert(qrcFilePath);
QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath); QrcParser::ConstPtr qrcFile = m_qrcCache.parsedPath(qrcFilePath.toString());
if (qrcFile.isNull()) if (qrcFile.isNull())
continue; continue;
callback(qrcFile); callback(qrcFile);
@@ -589,6 +606,8 @@ void ModelManagerInterface::updateProjectInfo(const ProjectInfo &pinfo, ProjectE
m_qrcContents = pinfo.resourceFileContents; m_qrcContents = pinfo.resourceFileContents;
for (const QString &newQrc : qAsConst(pinfo.allResourceFiles)) for (const QString &newQrc : qAsConst(pinfo.allResourceFiles))
m_qrcCache.addPath(newQrc, m_qrcContents.value(newQrc)); 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)) for (const QString &oldQrc : qAsConst(oldInfo.allResourceFiles))
m_qrcCache.removePath(oldQrc); m_qrcCache.removePath(oldQrc);
@@ -1180,6 +1199,29 @@ void ModelManagerInterface::maybeScan(const PathsAndLanguages &importPaths)
} }
} }
static QList<Utils::FilePath> minimalPrefixPaths(const QStringList &paths)
{
QList<Utils::FilePath> 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<Utils::FilePath> 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() void ModelManagerInterface::updateImportPaths()
{ {
if (m_indexerDisabled) if (m_indexerDisabled)
@@ -1243,6 +1285,7 @@ void ModelManagerInterface::updateImportPaths()
m_allImportPaths = allImportPaths; m_allImportPaths = allImportPaths;
m_activeBundles = activeBundles; m_activeBundles = activeBundles;
m_extendedBundles = extendedBundles; m_extendedBundles = extendedBundles;
m_applicationPaths = minimalPrefixPaths(allApplicationDirectories);
} }
@@ -1253,10 +1296,13 @@ void ModelManagerInterface::updateImportPaths()
QSet<QString> newLibraries; QSet<QString> newLibraries;
for (const Document::Ptr &doc : qAsConst(snapshot)) for (const Document::Ptr &doc : qAsConst(snapshot))
findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries); findNewLibraryImports(doc, snapshot, this, &importedFiles, &scannedPaths, &newLibraries);
for (const QString &path : qAsConst(allApplicationDirectories)) { for (const QString &pathStr : qAsConst(allApplicationDirectories)) {
allImportPaths.maybeInsert(FilePath::fromString(path), Dialect::Qml); Utils::FilePath path = Utils::FilePath::fromString(pathStr);
findNewQmlApplicationInPath(FilePath::fromString(path), snapshot, this, &newLibraries); allImportPaths.maybeInsert(path, Dialect::Qml);
findNewQmlApplicationInPath(path, snapshot, this, &newLibraries);
} }
for (const Utils::FilePath &qrcPath : generatedQrc(allApplicationDirectories))
updateQrcFile(qrcPath.toString());
updateSourceFiles(importedFiles, true); updateSourceFiles(importedFiles, true);
@@ -1668,4 +1714,47 @@ void ModelManagerInterface::resetCodeModel()
updateImportPaths(); 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 } // namespace QmlJS

View File

@@ -34,6 +34,7 @@
#include <utils/environment.h> #include <utils/environment.h>
#include <utils/futuresynchronizer.h> #include <utils/futuresynchronizer.h>
#include <utils/qrcparser.h> #include <utils/qrcparser.h>
#include <utils/filepath.h>
#include <QFuture> #include <QFuture>
#include <QHash> #include <QHash>
@@ -149,6 +150,7 @@ public:
ProjectExplorer::Project *project = nullptr, ProjectExplorer::Project *project = nullptr,
bool addDirs = false, bool addDirs = false,
QrcResourceSelector resources = AllQrcResources); QrcResourceSelector resources = AllQrcResources);
Utils::FilePath fileToSource(const Utils::FilePath &file);
QList<ProjectInfo> projectInfos() const; QList<ProjectInfo> projectInfos() const;
bool containsProject(ProjectExplorer::Project *project) const; bool containsProject(ProjectExplorer::Project *project) const;
@@ -254,6 +256,7 @@ private:
QmlJS::Snapshot m_validSnapshot; QmlJS::Snapshot m_validSnapshot;
QmlJS::Snapshot m_newestSnapshot; QmlJS::Snapshot m_newestSnapshot;
PathsAndLanguages m_allImportPaths; PathsAndLanguages m_allImportPaths;
QList<Utils::FilePath> m_applicationPaths;
QStringList m_defaultImportPaths; QStringList m_defaultImportPaths;
QmlJS::QmlLanguageBundles m_activeBundles; QmlJS::QmlLanguageBundles m_activeBundles;
QmlJS::QmlLanguageBundles m_extendedBundles; QmlJS::QmlLanguageBundles m_extendedBundles;

View File

@@ -264,13 +264,20 @@ void PluginDumper::qmlPluginTypeDumpDone(QtcProcess *process)
return; return;
const Snapshot snapshot = m_modelManager->snapshot(); const Snapshot snapshot = m_modelManager->snapshot();
LibraryInfo libraryInfo = snapshot.libraryInfo(libraryPath); 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); const QString errorMessages = qmlPluginDumpErrorMessage(process);
if (!privatePlugin) if (!privatePlugin)
ModelManagerInterface::writeWarning(qmldumpErrorMessage(libraryPath, errorMessages)); 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(); 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) void PluginDumper::pluginChanged(const QString &pluginLibrary)
{ {
const int pluginIndex = m_libraryToPluginIndex.value(pluginLibrary, -1); const int pluginIndex = m_libraryToPluginIndex.value(pluginLibrary, -1);
@@ -628,8 +618,7 @@ void PluginDumper::runQmlDump(const ModelManagerInterface::ProjectInfo &info,
process->setEnvironment(info.qmlDumpEnvironment); process->setEnvironment(info.qmlDumpEnvironment);
process->setWorkingDirectory(importPath); process->setWorkingDirectory(importPath);
process->setCommand({info.qmlDumpPath, arguments}); process->setCommand({info.qmlDumpPath, arguments});
connect(process, &QtcProcess::finished, this, [this, process] { qmlPluginTypeDumpDone(process); }); connect(process, &QtcProcess::done, this, [this, process] { qmlPluginTypeDumpDone(process); });
connect(process, &QtcProcess::errorOccurred, this, [this, process] { qmlPluginTypeDumpError(process); });
process->start(); process->start();
m_runningQmldumps.insert(process, importPath); m_runningQmldumps.insert(process, importPath);
} }

View File

@@ -60,7 +60,6 @@ private:
const QString &importUri, const QString &importVersion); const QString &importUri, const QString &importVersion);
Q_INVOKABLE void dumpAllPlugins(); Q_INVOKABLE void dumpAllPlugins();
void qmlPluginTypeDumpDone(Utils::QtcProcess *process); void qmlPluginTypeDumpDone(Utils::QtcProcess *process);
void qmlPluginTypeDumpError(Utils::QtcProcess *process);
void pluginChanged(const QString &pluginLibrary); void pluginChanged(const QString &pluginLibrary);
private: private:

View File

@@ -20,9 +20,13 @@ endif()
find_library(DbgEngLib dbgeng) find_library(DbgEngLib dbgeng)
set(ArchSuffix 32) set(ArchSuffix "32")
if (CMAKE_SIZEOF_VOID_P EQUAL 8) 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() endif()
add_qtc_library(qtcreatorcdbext SHARED add_qtc_library(qtcreatorcdbext SHARED

View File

@@ -1138,6 +1138,9 @@ void StringAspect::addToLayout(LayoutBuilder &builder)
&FancyLineEdit::textEdited, &FancyLineEdit::textEdited,
this, this,
&StringAspect::setValue); &StringAspect::setValue);
connect(d->m_lineEditDisplay, &FancyLineEdit::editingFinished, this, [this] {
setValue(d->m_lineEditDisplay->text());
});
} }
} }
if (d->m_useResetButton) { if (d->m_useResetButton) {
@@ -2442,6 +2445,10 @@ void AspectContainerData::append(const BaseAspect::Data::Ptr &data)
m_data.append(data); m_data.append(data);
} }
// BaseAspect::Data
BaseAspect::Data::~Data() = default;
void BaseAspect::Data::Ptr::operator=(const Ptr &other) void BaseAspect::Data::Ptr::operator=(const Ptr &other)
{ {
if (this == &other) if (this == &other)

View File

@@ -145,7 +145,7 @@ public:
// The (unique) address of the "owning" aspect's meta object is used as identifier. // The (unique) address of the "owning" aspect's meta object is used as identifier.
using ClassId = const void *; using ClassId = const void *;
virtual ~Data() = default; virtual ~Data();
Id id() const { return m_id; } Id id() const { return m_id; }
ClassId classId() const { return m_classId; } ClassId classId() const { return m_classId; }

View File

@@ -50,7 +50,7 @@ FilePath BuildableHelperLibrary::qtChooserToQmakePath(const FilePath &qtChooser)
proc.runBlocking(); proc.runBlocking();
if (proc.result() != ProcessResult::FinishedWithSuccess) if (proc.result() != ProcessResult::FinishedWithSuccess)
return {}; return {};
const QString output = proc.stdOut(); const QString output = proc.cleanedStdOut();
int pos = output.indexOf(toolDir); int pos = output.indexOf(toolDir);
if (pos == -1) if (pos == -1)
return {}; return {};

View File

@@ -277,8 +277,8 @@ void DeviceShell::startupFailed(const CommandLine &cmdLine)
bool DeviceShell::start() bool DeviceShell::start()
{ {
m_shellProcess = new QtcProcess(); m_shellProcess = new QtcProcess();
connect(m_shellProcess, &QtcProcess::done, this, [this] { emit done(); }); connect(m_shellProcess, &QtcProcess::done, m_shellProcess,
connect(m_shellProcess, &QtcProcess::errorOccurred, this, &DeviceShell::errorOccurred); [this] { emit done(m_shellProcess->resultData()); });
connect(m_shellProcess, &QObject::destroyed, this, [this] { m_shellProcess = nullptr; }); connect(m_shellProcess, &QObject::destroyed, this, [this] { m_shellProcess = nullptr; });
connect(&m_thread, &QThread::finished, m_shellProcess, [this] { closeShellProcess(); }); connect(&m_thread, &QThread::finished, m_shellProcess, [this] { closeShellProcess(); });

View File

@@ -36,6 +36,7 @@
namespace Utils { namespace Utils {
class CommandLine; class CommandLine;
class ProcessResultData;
class QtcProcess; class QtcProcess;
class DeviceShellImpl; class DeviceShellImpl;
@@ -69,8 +70,7 @@ public:
State state() const; State state() const;
signals: signals:
void done(); void done(const ProcessResultData &resultData);
void errorOccurred(QProcess::ProcessError error);
protected: protected:
virtual void startupFailed(const CommandLine &cmdLine); virtual void startupFailed(const CommandLine &cmdLine);

View File

@@ -945,8 +945,30 @@ QString FilePath::displayName(const QString &args) const
.arg(m_data, args, deviceName); .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 FilePath::fromString(const QString &filepath)
{ {
FilePath fn; FilePath fn;
@@ -1285,9 +1307,16 @@ FilePath FilePath::searchInDirectories(const FilePaths &dirs) const
return Environment::systemEnvironment().searchInDirectories(path(), dirs); return Environment::systemEnvironment().searchInDirectories(path(), dirs);
} }
FilePath FilePath::searchInPath(const QList<FilePath> &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 Environment FilePath::deviceEnvironment() const

View File

@@ -164,13 +164,16 @@ public:
[[nodiscard]] FilePath relativeChildPath(const FilePath &parent) const; [[nodiscard]] FilePath relativeChildPath(const FilePath &parent) const;
[[nodiscard]] FilePath relativePath(const FilePath &anchor) const; [[nodiscard]] FilePath relativePath(const FilePath &anchor) const;
[[nodiscard]] FilePath searchInDirectories(const QList<FilePath> &dirs) const; [[nodiscard]] FilePath searchInDirectories(const QList<FilePath> &dirs) const;
[[nodiscard]] FilePath searchInPath(const QList<FilePath> &additionalDirs = {}) const;
[[nodiscard]] Environment deviceEnvironment() const; [[nodiscard]] Environment deviceEnvironment() const;
[[nodiscard]] FilePath onDevice(const FilePath &deviceTemplate) const; [[nodiscard]] FilePath onDevice(const FilePath &deviceTemplate) const;
[[nodiscard]] FilePath withNewPath(const QString &newPath) const; [[nodiscard]] FilePath withNewPath(const QString &newPath) const;
void iterateDirectory(const std::function<bool(const FilePath &item)> &callBack, void iterateDirectory(const std::function<bool(const FilePath &item)> &callBack,
const FileFilter &filter) const; const FileFilter &filter) const;
enum PathAmending { AppendToPath, PrependToPath };
[[nodiscard]] FilePath searchInPath(const QList<FilePath> &additionalDirs = {},
PathAmending = AppendToPath) const;
// makes sure that capitalization of directories is canonical // makes sure that capitalization of directories is canonical
// on Windows and macOS. This is rarely needed. // on Windows and macOS. This is rarely needed.
[[nodiscard]] FilePath normalizedPathName() const; [[nodiscard]] FilePath normalizedPathName() const;

View File

@@ -31,6 +31,10 @@
#include <QOpenGLContext> #include <QOpenGLContext>
#endif #endif
#ifdef Q_OS_LINUX
#include <sys/sysinfo.h>
#endif
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
#include <qt_windows.h> #include <qt_windows.h>
#endif #endif
@@ -65,8 +69,9 @@ HostOsInfo::HostArchitecture HostOsInfo::hostArchitecture()
case PROCESSOR_ARCHITECTURE_IA64: case PROCESSOR_ARCHITECTURE_IA64:
return HostOsInfo::HostArchitectureItanium; return HostOsInfo::HostArchitectureItanium;
case PROCESSOR_ARCHITECTURE_ARM: case PROCESSOR_ARCHITECTURE_ARM:
case PROCESSOR_ARCHITECTURE_ARM64:
return HostOsInfo::HostArchitectureArm; return HostOsInfo::HostArchitectureArm;
case PROCESSOR_ARCHITECTURE_ARM64:
return HostOsInfo::HostArchitectureArm64;
default: default:
return HostOsInfo::HostArchitectureUnknown; return HostOsInfo::HostArchitectureUnknown;
} }
@@ -110,3 +115,27 @@ bool HostOsInfo::canCreateOpenGLContext(QString *errorMessage)
return canCreate; return canCreate;
#endif #endif
} }
optional<quint64> 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 {};
}

View File

@@ -27,6 +27,7 @@
#include "utils_global.h" #include "utils_global.h"
#include "optional.h"
#include "osspecificaspects.h" #include "osspecificaspects.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -60,7 +61,7 @@ public:
} }
enum HostArchitecture { HostArchitectureX86, HostArchitectureAMD64, HostArchitectureItanium, enum HostArchitecture { HostArchitectureX86, HostArchitectureAMD64, HostArchitectureItanium,
HostArchitectureArm, HostArchitectureUnknown }; HostArchitectureArm, HostArchitectureArm64, HostArchitectureUnknown };
static HostArchitecture hostArchitecture(); static HostArchitecture hostArchitecture();
static constexpr bool isWindowsHost() { return hostOs() == OsTypeWindows; } static constexpr bool isWindowsHost() { return hostOs() == OsTypeWindows; }
@@ -104,6 +105,8 @@ public:
static bool canCreateOpenGLContext(QString *errorMessage); static bool canCreateOpenGLContext(QString *errorMessage);
static optional<quint64> totalMemoryInstalledInBytes();
private: private:
static Qt::CaseSensitivity m_overrideFileNameCaseSensitivity; static Qt::CaseSensitivity m_overrideFileNameCaseSensitivity;
static bool m_useOverrideFileNameCaseSensitivity; static bool m_useOverrideFileNameCaseSensitivity;

View File

@@ -178,7 +178,7 @@ class PathChooserPrivate
public: public:
PathChooserPrivate(); PathChooserPrivate();
FilePath expandedPath(const QString &path) const; FilePath expandedPath(const FilePath &path) const;
QHBoxLayout *m_hLayout = nullptr; QHBoxLayout *m_hLayout = nullptr;
FancyLineEdit *m_lineEdit = 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()) if (input.isEmpty())
return {}; return {};
FilePath path = FilePath::fromUserInput(input); FilePath path = input;
Environment env = path.deviceEnvironment(); Environment env = path.deviceEnvironment();
m_environmentChange.applyToEnvironment(env); m_environmentChange.applyToEnvironment(env);
@@ -353,7 +353,7 @@ FilePath PathChooser::rawFilePath() const
FilePath PathChooser::filePath() const FilePath PathChooser::filePath() const
{ {
return d->expandedPath(rawFilePath().toString()); return d->expandedPath(rawFilePath());
} }
FilePath PathChooser::absoluteFilePath() const FilePath PathChooser::absoluteFilePath() const
@@ -529,11 +529,11 @@ FancyLineEdit::ValidationFunction PathChooser::defaultValidationFunction() const
bool PathChooser::validatePath(FancyLineEdit *edit, QString *errorMessage) 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()) { if (!d->m_defaultValue.isEmpty()) {
path = d->m_defaultValue; input = d->m_defaultValue;
} else { } else {
if (errorMessage) if (errorMessage)
*errorMessage = tr("The path must not be empty."); *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 (filePath.isEmpty()) {
if (errorMessage) 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; return false;
} }

View File

@@ -57,6 +57,7 @@ public:
const QLocale *locale = nullptr) const; const QLocale *locale = nullptr) const;
void collectResourceFilesForSourceFile(const QString &sourceFile, QStringList *res, void collectResourceFilesForSourceFile(const QString &sourceFile, QStringList *res,
const QLocale *locale = nullptr) const; const QLocale *locale = nullptr) const;
QrcParser::MatchResult longestReverseMatches(const QString &) const;
QStringList errorMessages() const; QStringList errorMessages() const;
QStringList languages() const; QStringList languages() const;
@@ -65,6 +66,7 @@ private:
const QStringList allUiLanguages(const QLocale *locale) const; const QStringList allUiLanguages(const QLocale *locale) const;
SMap m_resources; SMap m_resources;
SMap m_reverseResources;
SMap m_files; SMap m_files;
QStringList m_languages; QStringList m_languages;
QStringList m_errorMessages; QStringList m_errorMessages;
@@ -207,6 +209,11 @@ void QrcParser::collectFilesAtPath(const QString &path, QStringList *res, const
d->collectFilesAtPath(path, res, locale); 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. 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 else
accessPath = language + prefix + fileName; accessPath = language + prefix + fileName;
QStringList &resources = m_resources[accessPath]; QStringList &resources = m_resources[accessPath];
if (!resources.contains(filePath)) if (!resources.contains(filePath)) {
resources.append(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]; QStringList &files = m_files[filePath];
if (!files.contains(accessPath)) if (!files.contains(accessPath))
files.append(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 QStringList QrcParserPrivate::errorMessages() const
{ {
return m_errorMessages; return m_errorMessages;

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "utils_global.h" #include "utils_global.h"
#include "utils/filepath.h"
#include <QSharedPointer> #include <QSharedPointer>
#include <QString> #include <QString>
@@ -47,12 +48,20 @@ class QrcCachePrivate;
class QTCREATOR_UTILS_EXPORT QrcParser class QTCREATOR_UTILS_EXPORT QrcParser
{ {
public: public:
struct MatchResult
{
int matchDepth = {};
QStringList reversedPaths;
QList<Utils::FilePath> sourceFiles;
};
typedef QSharedPointer<QrcParser> Ptr; typedef QSharedPointer<QrcParser> Ptr;
typedef QSharedPointer<const QrcParser> ConstPtr; typedef QSharedPointer<const QrcParser> ConstPtr;
~QrcParser(); ~QrcParser();
bool parseFile(const QString &path, const QString &contents); bool parseFile(const QString &path, const QString &contents);
QString firstFileAtPath(const QString &path, const QLocale &locale) const; QString firstFileAtPath(const QString &path, const QLocale &locale) const;
void collectFilesAtPath(const QString &path, QStringList *res, const QLocale *locale = nullptr) 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; bool hasDirAtPath(const QString &path, const QLocale *locale = nullptr) const;
void collectFilesInPath(const QString &path, QMap<QString, QStringList> *res, bool addDirs = false, void collectFilesInPath(const QString &path, QMap<QString, QStringList> *res, bool addDirs = false,
const QLocale *locale = nullptr) const; const QLocale *locale = nullptr) const;

View File

@@ -1034,7 +1034,7 @@ QtcProcess::QtcProcess(QObject *parent)
Q_UNUSED(qProcessProcessErrorMeta) Q_UNUSED(qProcessProcessErrorMeta)
if (processLog().isDebugEnabled()) { if (processLog().isDebugEnabled()) {
connect(this, &QtcProcess::finished, [this] { connect(this, &QtcProcess::done, [this] {
if (!d->m_process.get()) if (!d->m_process.get())
return; return;
const QVariant n = d->m_process.get()->property(QTC_PROCESS_NUMBER); 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: " qCDebug(processLog).nospace() << "Process " << number << " finished: "
<< "result=" << int(result()) << "result=" << int(result())
<< ", ex=" << exitCode() << ", ex=" << exitCode()
<< ", " << stdOut().size() << " bytes stdout: " << ", " << cleanedStdOut().size() << " bytes stdout: "
<< stdOut().left(20) << cleanedStdOut().left(20)
<< ", " << stdErr().size() << " bytes stderr: " << ", " << cleanedStdErr().size() << " bytes stderr: "
<< stdErr().left(1000) << cleanedStdErr().left(1000)
<< ", " << msElapsed << " ms elapsed"; << ", " << msElapsed << " ms elapsed";
if (processStdoutLog().isDebugEnabled() && !stdOut().isEmpty()) if (processStdoutLog().isDebugEnabled() && !cleanedStdOut().isEmpty())
qCDebug(processStdoutLog).nospace() qCDebug(processStdoutLog).nospace()
<< "Process " << number << " sdout: " << stdOut(); << "Process " << number << " sdout: " << cleanedStdOut();
if (processStderrLog().isDebugEnabled() && !stdErr().isEmpty()) if (processStderrLog().isDebugEnabled() && !cleanedStdErr().isEmpty())
qCDebug(processStderrLog).nospace() 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); 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 \class Utils::SynchronousProcess
@@ -1691,8 +1685,8 @@ QString QtcProcess::allOutput() const
{ {
QTC_CHECK(d->m_stdOut.keepRawData); QTC_CHECK(d->m_stdOut.keepRawData);
QTC_CHECK(d->m_stdErr.keepRawData); QTC_CHECK(d->m_stdErr.keepRawData);
const QString out = stdOut(); const QString out = cleanedStdOut();
const QString err = stdErr(); const QString err = cleanedStdErr();
if (!out.isEmpty() && !err.isEmpty()) { if (!out.isEmpty() && !err.isEmpty()) {
QString result = out; QString result = out;
@@ -1748,12 +1742,12 @@ static QStringList splitLines(const QString &text)
const QStringList QtcProcess::stdOutLines() const const QStringList QtcProcess::stdOutLines() const
{ {
return splitLines(stdOut()); return splitLines(cleanedStdOut());
} }
const QStringList QtcProcess::stdErrLines() const const QStringList QtcProcess::stdErrLines() const
{ {
return splitLines(stdErr()); return splitLines(cleanedStdErr());
} }
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r) QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const QtcProcess &r)

View File

@@ -144,10 +144,10 @@ public:
// These (or some of them) may be potentially moved outside of the class. // 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)? // 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 // Helpers to find binaries. Do not use it for other path variables
// and file types. // and file types.
static QString locateBinary(const QString &binary);
static QString locateBinary(const QString &path, const QString &binary); static QString locateBinary(const QString &path, const QString &binary);
static QString normalizeNewlines(const QString &text); static QString normalizeNewlines(const QString &text);
@@ -189,8 +189,8 @@ public:
QString stdOut() const; // possibly with CR QString stdOut() const; // possibly with CR
QString stdErr() const; // possibly with CR QString stdErr() const; // possibly with CR
QString cleanedStdOut() const; // with CR removed QString cleanedStdOut() const; // with sequences of CR squashed and CR LF replaced by LF
QString cleanedStdErr() const; // with CR removed QString cleanedStdErr() const; // with sequences of CR squashed and CR LF replaced by LF
const QStringList stdOutLines() const; // split, CR removed const QStringList stdOutLines() const; // split, CR removed
const QStringList stdErrLines() const; // split, CR removed const QStringList stdErrLines() const; // split, CR removed

View File

@@ -271,8 +271,8 @@ void ShellCommand::run(QFutureInterface<void> &future)
proc.setExitCodeInterpreter(job.exitCodeInterpreter); proc.setExitCodeInterpreter(job.exitCodeInterpreter);
proc.setTimeoutS(job.timeoutS); proc.setTimeoutS(job.timeoutS);
runCommand(proc, job.command, job.workingDirectory); runCommand(proc, job.command, job.workingDirectory);
stdOut += proc.stdOut(); stdOut += proc.cleanedStdOut();
stdErr += proc.stdErr(); stdErr += proc.cleanedStdErr();
d->m_lastExecExitCode = proc.exitCode(); d->m_lastExecExitCode = proc.exitCode();
d->m_lastExecSuccess = proc.result() == ProcessResult::FinishedWithSuccess; d->m_lastExecSuccess = proc.result() == ProcessResult::FinishedWithSuccess;
if (!d->m_lastExecSuccess) if (!d->m_lastExecSuccess)
@@ -352,11 +352,11 @@ void ShellCommand::runFullySynchronous(QtcProcess &process, const FilePath &work
process.runBlocking(); process.runBlocking();
if (!d->m_aborted) { if (!d->m_aborted) {
const QString stdErr = process.stdErr(); const QString stdErr = process.cleanedStdErr();
if (!stdErr.isEmpty() && !(d->m_flags & SuppressStdErr)) if (!stdErr.isEmpty() && !(d->m_flags & SuppressStdErr))
emit append(stdErr); emit append(stdErr);
const QString stdOut = process.stdOut(); const QString stdOut = process.cleanedStdOut();
if (!stdOut.isEmpty() && d->m_flags & ShowStdOut) { if (!stdOut.isEmpty() && d->m_flags & ShowStdOut) {
if (d->m_flags & SilentOutput) if (d->m_flags & SilentOutput)
emit appendSilently(stdOut); emit appendSilently(stdOut);

View File

@@ -29,6 +29,11 @@
#include "hostosinfo.h" #include "hostosinfo.h"
#include "qtcassert.h" #include "qtcassert.h"
#ifdef QT_WIDGETS_LIB
#include <QApplication>
#include <QClipboard>
#endif
#include <QCoreApplication> #include <QCoreApplication>
#include <QDir> #include <QDir>
#include <QJsonArray> #include <QJsonArray>
@@ -469,4 +474,16 @@ QTCREATOR_UTILS_EXPORT QString languageNameFromLanguageCode(const QString &langu
return languageName; 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 } // namespace Utils

View File

@@ -122,4 +122,12 @@ QTCREATOR_UTILS_EXPORT QString wildcardToRegularExpression(const QString &origin
QTCREATOR_UTILS_EXPORT QString languageNameFromLanguageCode(const QString &languageCode); 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 } // namespace Utils

View File

@@ -36,4 +36,6 @@ TemporaryFile::TemporaryFile(const QString &pattern) :
QTC_CHECK(!QFileInfo(pattern).isAbsolute()); QTC_CHECK(!QFileInfo(pattern).isAbsolute());
} }
TemporaryFile::~TemporaryFile() = default;
} // namespace Utils } // namespace Utils

View File

@@ -35,6 +35,7 @@ class QTCREATOR_UTILS_EXPORT TemporaryFile : public QTemporaryFile
{ {
public: public:
explicit TemporaryFile(const QString &pattern); explicit TemporaryFile(const QString &pattern);
~TemporaryFile();
}; };
} // namespace Utils } // namespace Utils

View File

@@ -34,7 +34,7 @@ Project {
} }
Depends { name: "Qt"; submodules: ["concurrent", "network", "qml", "widgets", "xml"] } 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" } Depends { name: "app_version_header" }
files: [ files: [

View File

@@ -611,9 +611,11 @@ bool AndroidBuildApkStep::init()
QStringList argumentsPasswordConcealed = arguments; QStringList argumentsPasswordConcealed = arguments;
if (m_signPackage) { if (m_signPackage) {
arguments << "--sign" << m_keystorePath.toString() << m_certificateAlias arguments << "--release"
<< "--sign" << m_keystorePath.toString() << m_certificateAlias
<< "--storepass" << m_keystorePasswd; << "--storepass" << m_keystorePasswd;
argumentsPasswordConcealed << "--sign" << "******" argumentsPasswordConcealed << "--release"
<< "--sign" << "******"
<< "--storepass" << "******"; << "--storepass" << "******";
if (!m_certificatePasswd.isEmpty()) { if (!m_certificatePasswd.isEmpty()) {
arguments << "--keypass" << m_certificatePasswd; arguments << "--keypass" << m_certificatePasswd;
@@ -1065,7 +1067,7 @@ QAbstractItemModel *AndroidBuildApkStep::keystoreCertificates()
if (keytoolProc.result() > ProcessResult::FinishedWithError) if (keytoolProc.result() > ProcessResult::FinishedWithError)
QMessageBox::critical(nullptr, tr("Error"), tr("Failed to run keytool.")); QMessageBox::critical(nullptr, tr("Error"), tr("Failed to run keytool."));
else else
model = new CertificatesModel(keytoolProc.stdOut(), this); model = new CertificatesModel(keytoolProc.cleanedStdOut(), this);
return model; return model;
} }

View File

@@ -140,11 +140,16 @@ void AndroidDebugSupport::start()
solibSearchPath.append(qtVersion->qtSoPaths()); solibSearchPath.append(qtVersion->qtSoPaths());
solibSearchPath.append(uniquePaths(extraLibs)); solibSearchPath.append(uniquePaths(extraLibs));
FilePath buildDir = AndroidManager::buildDirectory(target);
const RunConfiguration *activeRunConfig = target->activeRunConfiguration(); const RunConfiguration *activeRunConfig = target->activeRunConfiguration();
FilePath buildDir;
if (activeRunConfig) if (activeRunConfig)
buildDir = activeRunConfig->buildTargetInfo().workingDirectory; solibSearchPath.append(activeRunConfig->buildTargetInfo().workingDirectory.toString());
solibSearchPath.append(buildDir.toString()); solibSearchPath.append(buildDir.toString());
const auto androidLibsPath = AndroidManager::androidBuildDirectory(target)
.pathAppended("libs")
.pathAppended(AndroidManager::apkDevicePreferredAbi(target))
.toString();
solibSearchPath.append(androidLibsPath);
solibSearchPath.removeDuplicates(); solibSearchPath.removeDuplicates();
setSolibSearchPath(solibSearchPath); setSolibSearchPath(solibSearchPath);
qCDebug(androidDebugSupportLog) << "SoLibSearchPath: "<<solibSearchPath; qCDebug(androidDebugSupportLog) << "SoLibSearchPath: "<<solibSearchPath;

View File

@@ -213,12 +213,12 @@ bool AndroidDeployQtStep::init()
m_serialNumber = info.serialNumber; m_serialNumber = info.serialNumber;
qCDebug(deployStepLog) << "Selected device info:" << info; qCDebug(deployStepLog) << "Selected device info:" << info;
gatherFilesToPull();
AndroidManager::setDeviceSerialNumber(target(), m_serialNumber); AndroidManager::setDeviceSerialNumber(target(), m_serialNumber);
AndroidManager::setDeviceApiLevel(target(), info.sdk); AndroidManager::setDeviceApiLevel(target(), info.sdk);
AndroidManager::setDeviceAbis(target(), info.cpuAbi); AndroidManager::setDeviceAbis(target(), info.cpuAbi);
gatherFilesToPull();
emit addOutput(tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage); emit addOutput(tr("Deploying to %1").arg(m_serialNumber), OutputFormat::NormalMessage);
m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value(); m_uninstallPreviousPackageRun = m_uninstallPreviousPackage->value();

View File

@@ -787,8 +787,8 @@ SdkToolResult AndroidManager::runCommand(const CommandLine &command,
qCDebug(androidManagerLog) << "Running command (sync):" << command.toUserOutput(); qCDebug(androidManagerLog) << "Running command (sync):" << command.toUserOutput();
cmdProc.setCommand(command); cmdProc.setCommand(command);
cmdProc.runBlocking(EventLoopMode::On); cmdProc.runBlocking(EventLoopMode::On);
cmdResult.m_stdOut = cmdProc.stdOut().trimmed(); cmdResult.m_stdOut = cmdProc.cleanedStdOut().trimmed();
cmdResult.m_stdErr = cmdProc.stdErr().trimmed(); cmdResult.m_stdErr = cmdProc.cleanedStdErr().trimmed();
cmdResult.m_success = cmdProc.result() == ProcessResult::FinishedWithSuccess; cmdResult.m_success = cmdProc.result() == ProcessResult::FinishedWithSuccess;
qCDebug(androidManagerLog) << "Command finshed (sync):" << command.toUserOutput() qCDebug(androidManagerLog) << "Command finshed (sync):" << command.toUserOutput()
<< "Success:" << cmdResult.m_success << "Success:" << cmdResult.m_success

View File

@@ -186,7 +186,7 @@ static void sdkManagerCommand(const AndroidConfig &config, const QStringList &ar
proc.runBlocking(EventLoopMode::On); proc.runBlocking(EventLoopMode::On);
if (assertionFound) { if (assertionFound) {
output.success = false; output.success = false;
output.stdOutput = proc.stdOut(); output.stdOutput = proc.cleanedStdOut();
output.stdError = QCoreApplication::translate("Android::Internal::AndroidSdkManager", output.stdError = QCoreApplication::translate("Android::Internal::AndroidSdkManager",
"The operation requires user interaction. " "The operation requires user interaction. "
"Use the \"sdkmanager\" command-line tool."); "Use the \"sdkmanager\" command-line tool.");

View File

@@ -51,10 +51,8 @@ BoostTestOutputReader::BoostTestOutputReader(const QFutureInterface<TestResultPt
, m_logLevel(log) , m_logLevel(log)
, m_reportLevel(report) , m_reportLevel(report)
{ {
if (m_testApplication) { if (m_testApplication)
connect(m_testApplication, &Utils::QtcProcess::finished, connect(m_testApplication, &Utils::QtcProcess::done, this, &BoostTestOutputReader::onDone);
this, &BoostTestOutputReader::onFinished);
}
} }
// content of "error:..." / "info:..." / ... messages // content of "error:..." / "info:..." / ... messages
@@ -406,7 +404,7 @@ TestResultPtr BoostTestOutputReader::createDefaultResult() const
return TestResultPtr(result); return TestResultPtr(result);
} }
void BoostTestOutputReader::onFinished() { void BoostTestOutputReader::onDone() {
int exitCode = m_testApplication->exitCode(); int exitCode = m_testApplication->exitCode();
if (m_reportLevel == ReportLevel::No && m_testCaseCount != -1) { if (m_reportLevel == ReportLevel::No && m_testCaseCount != -1) {
int reportedFailsAndSkips = m_summary[ResultType::Fail] + m_summary[ResultType::Skip]; int reportedFailsAndSkips = m_summary[ResultType::Fail] + m_summary[ResultType::Skip];

View File

@@ -47,7 +47,7 @@ protected:
TestResultPtr createDefaultResult() const override; TestResultPtr createDefaultResult() const override;
private: private:
void onFinished(); void onDone();
void sendCompleteInformation(); void sendCompleteInformation();
void handleMessageMatch(const QRegularExpressionMatch &match); void handleMessageMatch(const QRegularExpressionMatch &match);
void reportNoOutputFinish(const QString &description, ResultType type); void reportNoOutputFinish(const QString &description, ResultType type);

View File

@@ -45,9 +45,8 @@ GTestOutputReader::GTestOutputReader(const QFutureInterface<TestResultPtr> &futu
, m_projectFile(projectFile) , m_projectFile(projectFile)
{ {
if (m_testApplication) { if (m_testApplication) {
connect(m_testApplication, &Utils::QtcProcess::finished, connect(m_testApplication, &Utils::QtcProcess::done, this, [this] {
this, [this]() { const int exitCode = m_testApplication->exitCode();
int exitCode = m_testApplication->exitCode();
if (exitCode == 1 && !m_description.isEmpty()) { if (exitCode == 1 && !m_description.isEmpty()) {
createAndReportResult(tr("Running tests failed.\n %1\nExecutable: %2") createAndReportResult(tr("Running tests failed.\n %1\nExecutable: %2")
.arg(m_description).arg(id()), ResultType::MessageFatal); .arg(m_description).arg(id()), ResultType::MessageFatal);

View File

@@ -197,7 +197,7 @@ bool TestRunner::currentConfigValid()
m_fakeFutureInterface->reportFinished(); m_fakeFutureInterface->reportFinished();
onFinished(); onFinished();
} else { } else {
onProcessFinished(); onProcessDone();
} }
return false; return false;
} }
@@ -263,21 +263,20 @@ void TestRunner::scheduleNext()
return; return;
if (!m_currentConfig->project()) if (!m_currentConfig->project())
onProcessFinished(); onProcessDone();
setUpProcess(); setUpProcess();
QTC_ASSERT(m_currentProcess, onProcessFinished(); return); QTC_ASSERT(m_currentProcess, onProcessDone(); return);
QTC_ASSERT(!m_currentOutputReader, delete m_currentOutputReader); QTC_ASSERT(!m_currentOutputReader, delete m_currentOutputReader);
m_currentOutputReader = m_currentConfig->outputReader(*m_fakeFutureInterface, m_currentProcess); 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, connect(m_currentOutputReader, &TestOutputReader::newOutputLineAvailable,
TestResultsPane::instance(), &TestResultsPane::addOutputLine); TestResultsPane::instance(), &TestResultsPane::addOutputLine);
setUpProcessEnv(); setUpProcessEnv();
connect(m_currentProcess, &Utils::QtcProcess::finished, connect(m_currentProcess, &Utils::QtcProcess::done, this, &TestRunner::onProcessDone);
this, &TestRunner::onProcessFinished);
const int timeout = AutotestPlugin::settings()->timeout; const int timeout = AutotestPlugin::settings()->timeout;
m_cancelTimer.setInterval(timeout); m_cancelTimer.setInterval(timeout);
m_cancelTimer.start(); m_cancelTimer.start();
@@ -292,7 +291,7 @@ void TestRunner::scheduleNext()
reportResult(ResultType::MessageFatal, reportResult(ResultType::MessageFatal,
tr("Failed to start test for project \"%1\".").arg(m_currentConfig->displayName()) tr("Failed to start test for project \"%1\".").arg(m_currentConfig->displayName())
+ processInformation(m_currentProcess) + rcInfo(m_currentConfig)); + 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) { if (m_executingTests && m_currentConfig) {
QTC_CHECK(m_fakeFutureInterface); QTC_CHECK(m_fakeFutureInterface);

View File

@@ -90,7 +90,7 @@ private:
void setUpProcessEnv(); void setUpProcessEnv();
void scheduleNext(); void scheduleNext();
void cancelCurrent(CancelReason reason); void cancelCurrent(CancelReason reason);
void onProcessFinished(); void onProcessDone();
void resetInternalPointers(); void resetInternalPointers();
void runTests(); void runTests();

View File

@@ -91,12 +91,12 @@ UvscServerProvider::UvscServerProvider(const UvscServerProvider &other)
setEngineType(UvscEngineType); setEngineType(UvscEngineType);
} }
void UvscServerProvider::setToolsIniFile(const Utils::FilePath &toolsIniFile) void UvscServerProvider::setToolsIniFile(const FilePath &toolsIniFile)
{ {
m_toolsIniFile = toolsIniFile; m_toolsIniFile = toolsIniFile;
} }
Utils::FilePath UvscServerProvider::toolsIniFile() const FilePath UvscServerProvider::toolsIniFile() const
{ {
return m_toolsIniFile; return m_toolsIniFile;
} }
@@ -251,8 +251,7 @@ bool UvscServerProvider::fromMap(const QVariantMap &data)
return true; return true;
} }
Utils::FilePath UvscServerProvider::projectFilePath(DebuggerRunTool *runTool, FilePath UvscServerProvider::projectFilePath(DebuggerRunTool *runTool, QString &errorMessage) const
QString &errorMessage) const
{ {
const FilePath projectPath = buildProjectFilePath(runTool); const FilePath projectPath = buildProjectFilePath(runTool);
std::ofstream ofs(projectPath.toString().toStdString(), std::ofstream::out); std::ofstream ofs(projectPath.toString().toStdString(), std::ofstream::out);
@@ -332,12 +331,12 @@ void UvscServerProviderConfigWidget::discard()
IDebugServerProviderConfigWidget::discard(); IDebugServerProviderConfigWidget::discard();
} }
void UvscServerProviderConfigWidget::setToolsIniFile(const Utils::FilePath &toolsIniFile) void UvscServerProviderConfigWidget::setToolsIniFile(const FilePath &toolsIniFile)
{ {
m_toolsIniChooser->setFilePath(toolsIniFile); m_toolsIniChooser->setFilePath(toolsIniFile);
} }
Utils::FilePath UvscServerProviderConfigWidget::toolsIniFile() const FilePath UvscServerProviderConfigWidget::toolsIniFile() const
{ {
return m_toolsIniChooser->filePath(); return m_toolsIniChooser->filePath();
} }
@@ -386,21 +385,16 @@ UvscServerProviderRunner::UvscServerProviderRunner(ProjectExplorer::RunControl *
this->runControl()->setApplicationProcessHandle(pid); this->runControl()->setApplicationProcessHandle(pid);
reportStarted(); reportStarted();
}); });
connect(&m_process, &QtcProcess::finished, this, [this] { connect(&m_process, &QtcProcess::done, this, [this] {
const QProcess::ProcessError error = m_process.error(); appendMessage(m_process.exitMessage(), NormalMessageFormat);
const QString message = (error == QProcess::UnknownError)
? m_process.exitMessage()
: userMessageForProcessError(error, m_process.commandLine().executable());
appendMessage(message, Utils::NormalMessageFormat);
reportStopped(); reportStopped();
}); });
} }
void UvscServerProviderRunner::start() void UvscServerProviderRunner::start()
{ {
const QString msg = RunControl::tr("Starting %1 ...") const QString msg = RunControl::tr("Starting %1 ...").arg(m_process.commandLine().displayName());
.arg(m_process.commandLine().toUserOutput()); appendMessage(msg, NormalMessageFormat);
appendMessage(msg, Utils::NormalMessageFormat);
m_process.start(); m_process.start();
} }

View File

@@ -153,7 +153,7 @@ bool BazaarClient::synchronousUncommit(const FilePath &workingDir,
QtcProcess proc; QtcProcess proc;
vcsFullySynchronousExec(proc, workingDir, args); vcsFullySynchronousExec(proc, workingDir, args);
VcsOutputWindow::append(proc.stdOut()); VcsOutputWindow::append(proc.cleanedStdOut());
return proc.result() == ProcessResult::FinishedWithSuccess; return proc.result() == ProcessResult::FinishedWithSuccess;
} }

View File

@@ -34,11 +34,16 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/genericconstants.h> #include <utils/genericconstants.h>
#include <utils/mimeutils.h> #include <utils/mimeutils.h>
#include <utils/qtcprocess.h>
#include <QFile> #include <QFile>
#include <QFileInfo> #include <QFileInfo>
#include <QRegularExpression>
#include <QVersionNumber>
#include <QXmlStreamReader> #include <QXmlStreamReader>
using namespace Utils;
namespace Beautifier { namespace Beautifier {
namespace Internal { namespace Internal {
@@ -47,12 +52,65 @@ const char COMMAND[] = "command";
const char SUPPORTED_MIME[] = "supportedMime"; 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) AbstractSettings::AbstractSettings(const QString &name, const QString &ending)
: m_ending(ending) : m_ending(ending)
, m_styleDir(Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME) , m_styleDir(Core::ICore::userResourcePath(Beautifier::Constants::SETTINGS_DIRNAME)
.pathAppended(name) .pathAppended(name)
.toString()) .toString())
, m_name(name) , 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); 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; return;
m_command = command; m_command = cmd;
updateVersion(); 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 m_versionUpdater->setVersionRegExp(versionRegExp);
// in m_version.
} }
QString AbstractSettings::supportedMimeTypesAsString() const QString AbstractSettings::supportedMimeTypesAsString() const
@@ -157,7 +214,7 @@ void AbstractSettings::setSupportedMimeTypes(const QString &mimes)
const QStringList stringTypes = mimes.split(';'); const QStringList stringTypes = mimes.split(';');
QStringList types; QStringList types;
for (const QString &type : stringTypes) { for (const QString &type : stringTypes) {
const Utils::MimeType mime = Utils::mimeTypeForName(type.trimmed()); const MimeType mime = mimeTypeForName(type.trimmed());
if (!mime.isValid()) if (!mime.isValid())
continue; continue;
const QString canonicalName = mime.name(); const QString canonicalName = mime.name();
@@ -179,8 +236,8 @@ bool AbstractSettings::isApplicable(const Core::IDocument *document) const
if (m_supportedMimeTypes.isEmpty()) if (m_supportedMimeTypes.isEmpty())
return true; return true;
const Utils::MimeType documentMimeType = Utils::mimeTypeForName(document->mimeType()); const MimeType documentMimeType = mimeTypeForName(document->mimeType());
return Utils::anyOf(m_supportedMimeTypes, [&documentMimeType](const QString &mime) { return anyOf(m_supportedMimeTypes, [&documentMimeType](const QString &mime) {
return documentMimeType.inherits(mime); return documentMimeType.inherits(mime);
}); });
} }
@@ -246,7 +303,7 @@ void AbstractSettings::save()
continue; continue;
} }
Utils::FileSaver saver(Utils::FilePath::fromUserInput(fi.absoluteFilePath())); FileSaver saver(FilePath::fromUserInput(fi.absoluteFilePath()));
if (saver.hasError()) { if (saver.hasError()) {
BeautifierPlugin::showError(tr("Cannot open file \"%1\": %2.") BeautifierPlugin::showError(tr("Cannot open file \"%1\": %2.")
.arg(saver.filePath().toUserOutput()) .arg(saver.filePath().toUserOutput())

View File

@@ -35,12 +35,21 @@
#include <QStringList> #include <QStringList>
#include <QVector> #include <QVector>
#include <memory>
QT_BEGIN_NAMESPACE
class QRegularExpression;
class QVersionNumber;
QT_END_NAMESPACE
namespace Core { class IDocument; } namespace Core { class IDocument; }
namespace Utils { class FilePath; } namespace Utils { class FilePath; }
namespace Beautifier { namespace Beautifier {
namespace Internal { namespace Internal {
class VersionUpdater;
class AbstractSettings : public QObject class AbstractSettings : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -66,9 +75,8 @@ public:
virtual QString styleFileName(const QString &key) const; virtual QString styleFileName(const QString &key) const;
Utils::FilePath command() const; Utils::FilePath command() const;
void setCommand(const QString &command); void setCommand(const QString &cmd);
int version() const; QVersionNumber version() const;
virtual void updateVersion();
QString supportedMimeTypesAsString() const; QString supportedMimeTypesAsString() const;
void setSupportedMimeTypes(const QString &mimes); void setSupportedMimeTypes(const QString &mimes);
@@ -81,9 +89,10 @@ signals:
void supportedMimeTypesChanged(); void supportedMimeTypesChanged();
protected: protected:
void setVersionRegExp(const QRegularExpression &versionRegExp);
QMap<QString, QString> m_styles; QMap<QString, QString> m_styles;
QMap<QString, QVariant> m_settings; QMap<QString, QVariant> m_settings;
int m_version = 0;
QString m_ending; QString m_ending;
QDir m_styleDir; QDir m_styleDir;
@@ -92,6 +101,7 @@ protected:
private: private:
QString m_name; QString m_name;
std::unique_ptr<VersionUpdater> m_versionUpdater;
QStringList m_stylesToRemove; QStringList m_stylesToRemove;
QSet<QString> m_changedStyles; QSet<QString> m_changedStyles;
QString m_command; QString m_command;

View File

@@ -53,6 +53,7 @@
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
#include <QVersionNumber>
using namespace TextEditor; using namespace TextEditor;
@@ -150,10 +151,10 @@ Command ArtisticStyle::command(const QString &cfgFile) const
command.addOption("-q"); command.addOption("-q");
command.addOption("--options=" + cfgFile); command.addOption("--options=" + cfgFile);
const int version = m_settings.version(); const QVersionNumber version = m_settings.version();
if (version > ArtisticStyleSettings::Version_2_03) { if (version > QVersionNumber(2, 3)) {
command.setProcessing(Command::PipeProcessing); command.setProcessing(Command::PipeProcessing);
if (version == ArtisticStyleSettings::Version_2_04) if (version == QVersionNumber(2, 4))
command.setPipeAddsNewline(true); command.setPipeAddsNewline(true);
command.setReturnsCRLF(Utils::HostOsInfo::isWindowsHost()); command.setReturnsCRLF(Utils::HostOsInfo::isWindowsHost());
command.addOption("-z2"); command.addOption("-z2");

View File

@@ -57,9 +57,7 @@ const char SETTINGS_NAME[] = "artisticstyle";
ArtisticStyleSettings::ArtisticStyleSettings() : ArtisticStyleSettings::ArtisticStyleSettings() :
AbstractSettings(SETTINGS_NAME, ".astyle") AbstractSettings(SETTINGS_NAME, ".astyle")
{ {
connect(&m_versionWatcher, &QFutureWatcherBase::finished, setVersionRegExp(QRegularExpression("([2-9]{1})\\.([0-9]{1,2})(\\.[1-9]{1})?$"));
this, &ArtisticStyleSettings::helperSetVersion);
setCommand("astyle"); setCommand("astyle");
m_settings.insert(USE_OTHER_FILES, QVariant(true)); m_settings.insert(USE_OTHER_FILES, QVariant(true));
m_settings.insert(USE_SPECIFIC_CONFIG_FILE, QVariant(false)); m_settings.insert(USE_SPECIFIC_CONFIG_FILE, QVariant(false));
@@ -70,48 +68,6 @@ ArtisticStyleSettings::ArtisticStyleSettings() :
read(); 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 bool ArtisticStyleSettings::useOtherFiles() const
{ {
return m_settings.value(USE_OTHER_FILES).toBool(); 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)); 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())); m_settings.insert(SPECIFIC_CONFIG_FILE, QVariant(specificConfigFile.toString()));
} }
@@ -182,7 +138,7 @@ QString ArtisticStyleSettings::documentationFilePath() const
void ArtisticStyleSettings::createDocumentationFile() const void ArtisticStyleSettings::createDocumentationFile() const
{ {
Utils::QtcProcess process; QtcProcess process;
process.setTimeoutS(2); process.setTimeoutS(2);
process.setCommand({command(), {"-h"}}); process.setCommand({command(), {"-h"}});
process.runBlocking(); process.runBlocking();
@@ -204,7 +160,7 @@ void ArtisticStyleSettings::createDocumentationFile() const
stream.writeStartElement(Constants::DOCUMENTATION_XMLROOT); stream.writeStartElement(Constants::DOCUMENTATION_XMLROOT);
// astyle writes its output to 'error'... // 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 keys;
QStringList docu; QStringList docu;
for (QString line : lines) { for (QString line : lines) {

View File

@@ -29,9 +29,6 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <QFuture>
#include <QFutureWatcher>
namespace Beautifier { namespace Beautifier {
namespace Internal { namespace Internal {
@@ -40,15 +37,8 @@ class ArtisticStyleSettings : public AbstractSettings
Q_OBJECT Q_OBJECT
public: public:
enum ArtisticStyleVersion {
Version_2_03 = 203,
Version_2_04 = 204
};
ArtisticStyleSettings(); ArtisticStyleSettings();
void updateVersion() override;
bool useOtherFiles() const; bool useOtherFiles() const;
void setUseOtherFiles(bool useOtherFiles); void setUseOtherFiles(bool useOtherFiles);
@@ -69,11 +59,6 @@ public:
QString documentationFilePath() const override; QString documentationFilePath() const override;
void createDocumentationFile() const override; void createDocumentationFile() const override;
private:
void helperSetVersion();
QFuture<int> m_versionFuture;
QFutureWatcher<int> m_versionWatcher;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -49,6 +49,7 @@
#include <QAction> #include <QAction>
#include <QMenu> #include <QMenu>
#include <QVersionNumber>
using namespace TextEditor; using namespace TextEditor;
@@ -180,7 +181,7 @@ Command Uncrustify::command(const QString &cfgFile, bool fragment) const
Command command; Command command;
command.setExecutable(m_settings.command().toString()); command.setExecutable(m_settings.command().toString());
command.setProcessing(Command::PipeProcessing); command.setProcessing(Command::PipeProcessing);
if (m_settings.version() >= 62) { if (m_settings.version() >= QVersionNumber(0, 62)) {
command.addOption("--assume"); command.addOption("--assume");
command.addOption("%file"); command.addOption("%file");
} else { } else {

View File

@@ -30,7 +30,6 @@
#include "../beautifierconstants.h" #include "../beautifierconstants.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
#include <QDateTime> #include <QDateTime>
@@ -56,6 +55,7 @@ const char SETTINGS_NAME[] = "uncrustify";
UncrustifySettings::UncrustifySettings() : UncrustifySettings::UncrustifySettings() :
AbstractSettings(SETTINGS_NAME, ".cfg") AbstractSettings(SETTINGS_NAME, ".cfg")
{ {
setVersionRegExp(QRegularExpression("([0-9]{1})\\.([0-9]{2})"));
setCommand("uncrustify"); setCommand("uncrustify");
m_settings.insert(USE_OTHER_FILES, QVariant(true)); m_settings.insert(USE_OTHER_FILES, QVariant(true));
m_settings.insert(USE_HOME_FILE, QVariant(false)); 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 Internal
} // namespace Beautifier } // namespace Beautifier

View File

@@ -26,9 +26,6 @@
#pragma once #pragma once
#include "../abstractsettings.h" #include "../abstractsettings.h"
#include <utils/fileutils.h>
namespace Utils { class QtcProcess; }
namespace Beautifier { namespace Beautifier {
namespace Internal { namespace Internal {
@@ -59,16 +56,11 @@ public:
QString documentationFilePath() const override; QString documentationFilePath() const override;
void createDocumentationFile() const override; void createDocumentationFile() const override;
void updateVersion() override;
Utils::FilePath specificConfigFile() const; Utils::FilePath specificConfigFile() const;
void setSpecificConfigFile(const Utils::FilePath &filePath); void setSpecificConfigFile(const Utils::FilePath &filePath);
bool useSpecificConfigFile() const; bool useSpecificConfigFile() const;
void setUseSpecificConfigFile(bool useConfigFile); void setUseSpecificConfigFile(bool useConfigFile);
private:
std::unique_ptr<Utils::QtcProcess> m_versionProcess;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -88,8 +88,8 @@ public:
private: private:
void handleDone() void handleDone()
{ {
const QString stdOut = m_appRunner.stdOut(); const QString stdOut = m_appRunner.cleanedStdOut();
const QString stdErr = m_appRunner.stdErr(); const QString stdErr = m_appRunner.cleanedStdErr();
// FIXME: Needed in a post-adb world? // FIXME: Needed in a post-adb world?
// adb does not forward exit codes and all stderr goes to stdout. // adb does not forward exit codes and all stderr goes to stdout.

View File

@@ -55,7 +55,7 @@ public:
setId("QdbDebuggeeRunner"); setId("QdbDebuggeeRunner");
connect(&m_launcher, &QtcProcess::started, this, &RunWorker::reportStarted); 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] { connect(&m_launcher, &QtcProcess::readyReadStandardOutput, [this] {
appendMessage(QString::fromUtf8(m_launcher.readAllStandardOutput()), StdOutFormat); appendMessage(QString::fromUtf8(m_launcher.readAllStandardOutput()), StdOutFormat);

View File

@@ -22,6 +22,7 @@ add_qtc_plugin(ClangCodeModel
clangdquickfixfactory.cpp clangdquickfixfactory.h clangdquickfixfactory.cpp clangdquickfixfactory.h
clangdqpropertyhighlighter.cpp clangdqpropertyhighlighter.h clangdqpropertyhighlighter.cpp clangdqpropertyhighlighter.h
clangdsemantichighlighting.cpp clangdsemantichighlighting.h clangdsemantichighlighting.cpp clangdsemantichighlighting.h
clangdswitchdecldef.cpp clangdswitchdecldef.h
clangeditordocumentprocessor.cpp clangeditordocumentprocessor.h clangeditordocumentprocessor.cpp clangeditordocumentprocessor.h
clangfixitoperation.cpp clangfixitoperation.h clangfixitoperation.cpp clangfixitoperation.h
clangdlocatorfilters.cpp clangdlocatorfilters.h clangdlocatorfilters.cpp clangdlocatorfilters.h

View File

@@ -46,6 +46,8 @@ QtcPlugin {
"clangdquickfixfactory.h", "clangdquickfixfactory.h",
"clangdsemantichighlighting.cpp", "clangdsemantichighlighting.cpp",
"clangdsemantichighlighting.h", "clangdsemantichighlighting.h",
"clangdswitchdecldef.cpp",
"clangdswitchdecldef.h",
"clangeditordocumentprocessor.cpp", "clangeditordocumentprocessor.cpp",
"clangeditordocumentprocessor.h", "clangeditordocumentprocessor.h",
"clangfixitoperation.cpp", "clangfixitoperation.cpp",

View File

@@ -30,6 +30,7 @@
#include "clangdast.h" #include "clangdast.h"
#include "clangdfollowsymbol.h" #include "clangdfollowsymbol.h"
#include "clangdlocatorfilters.h" #include "clangdlocatorfilters.h"
#include "clangdswitchdecldef.h"
#include "clangpreprocessorassistproposalitem.h" #include "clangpreprocessorassistproposalitem.h"
#include "clangtextmark.h" #include "clangtextmark.h"
#include "clangutils.h" #include "clangutils.h"
@@ -59,7 +60,6 @@
#include <cppeditor/semantichighlighter.h> #include <cppeditor/semantichighlighter.h>
#include <cppeditor/cppsemanticinfo.h> #include <cppeditor/cppsemanticinfo.h>
#include <languageclient/diagnosticmanager.h> #include <languageclient/diagnosticmanager.h>
#include <languageclient/documentsymbolcache.h>
#include <languageclient/languageclientcompletionassist.h> #include <languageclient/languageclientcompletionassist.h>
#include <languageclient/languageclientfunctionhint.h> #include <languageclient/languageclientfunctionhint.h>
#include <languageclient/languageclienthoverhandler.h> #include <languageclient/languageclienthoverhandler.h>
@@ -117,8 +117,8 @@ namespace ClangCodeModel {
namespace Internal { namespace Internal {
Q_LOGGING_CATEGORY(clangdLog, "qtc.clangcodemodel.clangd", QtWarningMsg); 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(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", static Q_LOGGING_CATEGORY(clangdLogCompletion, "qtc.clangcodemodel.clangd.completion",
QtWarningMsg); QtWarningMsg);
static QString indexingToken() { return "backgroundIndexProgress"; } static QString indexingToken() { return "backgroundIndexProgress"; }
@@ -310,58 +310,6 @@ public:
bool categorize = CppEditor::codeModelSettings()->categorizeFindReferences(); 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<ClangdAstNode> 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<QList<DocumentSymbol>>(&*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<DocumentSymbol>());
}
return {};
}
const quint64 id;
const QPointer<TextDocument> document;
const DocumentUri uri;
const QTextCursor cursor;
const QPointer<CppEditor::CppEditorWidget> editorWidget;
Utils::LinkHandler callback;
Utils::optional<DocumentSymbolsResult> docSymbols;
Utils::optional<ClangdAstNode> ast;
};
class LocalRefsData { class LocalRefsData {
public: public:
LocalRefsData(quint64 id, TextDocument *doc, const QTextCursor &cursor, LocalRefsData(quint64 id, TextDocument *doc, const QTextCursor &cursor,
@@ -699,7 +647,7 @@ public:
const CppEditor::ClangdSettings::Data settings; const CppEditor::ClangdSettings::Data settings;
QHash<quint64, ReferencesData> runningFindUsages; QHash<quint64, ReferencesData> runningFindUsages;
ClangdFollowSymbol *followSymbol = nullptr; ClangdFollowSymbol *followSymbol = nullptr;
Utils::optional<SwitchDeclDefData> switchDeclDefData; ClangdSwitchDeclDef *switchDeclDef = nullptr;
Utils::optional<LocalRefsData> localRefsData; Utils::optional<LocalRefsData> localRefsData;
Utils::optional<QVersionNumber> versionNumber; Utils::optional<QVersionNumber> versionNumber;
@@ -741,6 +689,7 @@ public:
private: private:
QIcon icon() const override; QIcon icon() const override;
QString text() const override;
}; };
class ClangdClient::ClangdCompletionAssistProcessor : public LanguageClientCompletionAssistProcessor class ClangdClient::ClangdCompletionAssistProcessor : public LanguageClientCompletionAssistProcessor
@@ -1015,15 +964,6 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
QTC_CHECK(d->runningFindUsages.isEmpty()); 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(); start();
} }
@@ -1682,26 +1622,13 @@ void ClangdClient::switchDeclDef(TextDocument *document, const QTextCursor &curs
qCDebug(clangdLog) << "switch decl/dev requested" << document->filePath() qCDebug(clangdLog) << "switch decl/dev requested" << document->filePath()
<< cursor.blockNumber() << cursor.positionInBlock(); << cursor.blockNumber() << cursor.positionInBlock();
d->switchDeclDefData.emplace(++d->nextJobId, document, cursor, editorWidget, callback); if (d->switchDeclDef)
delete d->switchDeclDef;
// Retrieve AST and document symbols. d->switchDeclDef = new ClangdSwitchDeclDef(this, document, cursor, editorWidget, callback);
const auto astHandler = [this, id = d->switchDeclDefData->id](const ClangdAstNode &ast, connect(d->switchDeclDef, &ClangdSwitchDeclDef::done, this, [this] {
const MessageId &) { delete d->switchDeclDef;
qCDebug(clangdLog) << "received ast for decl/def switch"; d->switchDeclDef = nullptr;
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);
} }
void ClangdClient::switchHeaderSource(const Utils::FilePath &filePath, bool inNextSplit) 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}; 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<ClangdAstNode> 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<QString> ClangdClient::Private::getContainingFunctionName( Utils::optional<QString> ClangdClient::Private::getContainingFunctionName(
const ClangdAstPath &astPath, const Range& range) const ClangdAstPath &astPath, const Range& range)
{ {
@@ -2551,6 +2449,8 @@ ClangdCompletionItem::SpecialQtType ClangdCompletionItem::getQtType(const Comple
QIcon ClangdCompletionItem::icon() const QIcon ClangdCompletionItem::icon() const
{ {
if (isDeprecated())
return Utils::Icons::WARNING.icon();
const SpecialQtType qtType = getQtType(item()); const SpecialQtType qtType = getQtType(item());
switch (qtType) { switch (qtType) {
case SpecialQtType::Signal: case SpecialQtType::Signal:
@@ -2566,6 +2466,14 @@ QIcon ClangdCompletionItem::icon() const
return LanguageClientCompletionItem::icon(); 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, MessageId ClangdClient::Private::getAndHandleAst(const TextDocOrFile &doc,
const AstHandler &astHandler, const AstHandler &astHandler,
AstCallbackMode callbackMode, const Range &range) AstCallbackMode callbackMode, const Range &range)

View File

@@ -51,6 +51,7 @@ namespace Internal {
class ClangdAstNode; class ClangdAstNode;
Q_DECLARE_LOGGING_CATEGORY(clangdLog); Q_DECLARE_LOGGING_CATEGORY(clangdLog);
Q_DECLARE_LOGGING_CATEGORY(clangdLogAst);
void setupClangdConfigFile(); void setupClangdConfigFile();

View File

@@ -38,6 +38,7 @@
#include <texteditor/codeassist/iassistprovider.h> #include <texteditor/codeassist/iassistprovider.h>
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <QApplication>
#include <QPointer> #include <QPointer>
using namespace CppEditor; using namespace CppEditor;
@@ -133,6 +134,7 @@ public:
SymbolDataList symbolsToDisplay; SymbolDataList symbolsToDisplay;
std::set<FilePath> openedFiles; std::set<FilePath> openedFiles;
VirtualFunctionAssistProcessor *virtualFuncAssistProcessor = nullptr; VirtualFunctionAssistProcessor *virtualFuncAssistProcessor = nullptr;
QMetaObject::Connection focusChangedConnection;
bool finished = false; bool finished = false;
}; };
@@ -143,6 +145,16 @@ ClangdFollowSymbol::ClangdFollowSymbol(ClangdClient *client, const QTextCursor &
d(new Private(this, client, cursor, editorWidget, document->filePath(), callback, d(new Private(this, client, cursor, editorWidget, document->filePath(), callback,
openInSplit)) 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 // 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 // AST node corresponding to the cursor position, so we can find out whether
// we have to look for overrides. // 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 // 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. // 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); editorWidget->invokeTextEditorWidgetAssist(FollowSymbol, &virtualFuncAssistProvider);
}
if (!pendingGotoImplRequests.isEmpty()) if (!pendingGotoImplRequests.isEmpty())
return; return;

View File

@@ -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 <cppeditor/cppeditorwidget.h>
#include <languageclient/documentsymbolcache.h>
#include <languageserverprotocol/lsptypes.h>
#include <texteditor/textdocument.h>
#include <utils/optional.h>
#include <utils/qtcassert.h>
#include <QApplication>
#include <QTextCursor>
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<ClangdAstNode> getFunctionNode() const;
QTextCursor cursorForFunctionName(const ClangdAstNode &functionNode) const;
void handleDeclDefSwitchReplies();
ClangdSwitchDeclDef * const q;
ClangdClient * const client;
const QPointer<TextDocument> document;
const DocumentUri uri;
const QTextCursor cursor;
const QPointer<CppEditorWidget> editorWidget;
const LinkHandler callback;
optional<ClangdAstNode> ast;
optional<DocumentSymbolsResult> 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<ClangdAstNode> 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<QList<DocumentSymbol>>(&*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<DocumentSymbol>());
}
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<ClangdAstNode> 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

View File

@@ -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 <utils/link.h>
#include <QObject>
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

View File

@@ -62,10 +62,12 @@
#include <projectexplorer/taskhub.h> #include <projectexplorer/taskhub.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/infobar.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/runextensions.h> #include <utils/runextensions.h>
#include <QApplication> #include <QApplication>
#include <QLabel>
#include <QMenu> #include <QMenu>
#include <QTextBlock> #include <QTextBlock>
#include <QTimer> #include <QTimer>
@@ -124,6 +126,40 @@ static Client *clientForGeneratedFile(const Utils::FilePath &filePath)
return nullptr; 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.<br>"
"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.<br>"
"You can enable/disable and fine-tune clangd <a href=\"dummy\">here</a>."));
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() ClangModelManagerSupport::ClangModelManagerSupport()
{ {
QTC_CHECK(!m_instance); QTC_CHECK(!m_instance);
@@ -132,6 +168,7 @@ ClangModelManagerSupport::ClangModelManagerSupport()
watchForExternalChanges(); watchForExternalChanges();
watchForInternalChanges(); watchForInternalChanges();
setupClangdConfigFile(); setupClangdConfigFile();
checkSystemForClangdSuitability();
cppModelManager()->setCurrentDocumentFilter(std::make_unique<ClangdCurrentDocumentFilter>()); cppModelManager()->setCurrentDocumentFilter(std::make_unique<ClangdCurrentDocumentFilter>());
cppModelManager()->setLocatorFilter(std::make_unique<ClangGlobalSymbolFilter>()); cppModelManager()->setLocatorFilter(std::make_unique<ClangGlobalSymbolFilter>());
cppModelManager()->setClassesFilter(std::make_unique<ClangClassesFilter>()); cppModelManager()->setClassesFilter(std::make_unique<ClangClassesFilter>());

View File

@@ -29,7 +29,6 @@
#include "clangdclient.h" #include "clangdclient.h"
#include "clangdiagnostictooltipwidget.h" #include "clangdiagnostictooltipwidget.h"
#include "clangeditordocumentprocessor.h" #include "clangeditordocumentprocessor.h"
#include "clangmodelmanagersupport.h"
#include "clangutils.h" #include "clangutils.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
@@ -42,12 +41,11 @@
#include <utils/fadingindicator.h> #include <utils/fadingindicator.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/stringutils.h>
#include <utils/theme/theme.h> #include <utils/theme/theme.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <QAction> #include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QLayout> #include <QLayout>
#include <QRegularExpression> #include <QRegularExpression>
#include <QRegularExpressionMatch> #include <QRegularExpressionMatch>
@@ -319,7 +317,7 @@ ClangdTextMark::ClangdTextMark(const FilePath &filePath,
QObject::connect(action, &QAction::triggered, [diag = m_diagnostic]() { QObject::connect(action, &QAction::triggered, [diag = m_diagnostic]() {
const QString text = ClangDiagnosticWidget::createText({diag}, const QString text = ClangDiagnosticWidget::createText({diag},
ClangDiagnosticWidget::InfoBar); ClangDiagnosticWidget::InfoBar);
QApplication::clipboard()->setText(text, QClipboard::Clipboard); setClipboardAndSelection(text);
}); });
actions << action; actions << action;

View File

@@ -132,7 +132,7 @@ void ClangToolRunner::onProcessDone()
if (m_process.result() == ProcessResult::StartFailed) { if (m_process.result() == ProcessResult::StartFailed) {
emit finishedWithFailure(generalProcessError(m_name), commandlineAndOutput()); emit finishedWithFailure(generalProcessError(m_name), commandlineAndOutput());
} else if (m_process.result() == ProcessResult::FinishedWithSuccess) { } 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); emit finishedWithSuccess(m_fileToAnalyze);
} else if (m_process.result() == ProcessResult::FinishedWithError) { } else if (m_process.result() == ProcessResult::FinishedWithError) {
emit finishedWithFailure(finishedWithBadExitCode(m_name, m_process.exitCode()), emit finishedWithFailure(finishedWithBadExitCode(m_name, m_process.exitCode()),
@@ -149,7 +149,7 @@ QString ClangToolRunner::commandlineAndOutput() const
"Output:\n%3") "Output:\n%3")
.arg(m_commandLine.toUserOutput()) .arg(m_commandLine.toUserOutput())
.arg(m_process.error()) .arg(m_process.error())
.arg(m_process.stdOut()); .arg(m_process.cleanedStdOut());
} }
} // namespace Internal } // namespace Internal

View File

@@ -30,10 +30,9 @@
#include "diagnosticconfigswidget.h" #include "diagnosticconfigswidget.h"
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <utils/stringutils.h>
#include <QAction> #include <QAction>
#include <QApplication>
#include <QClipboard>
namespace ClangTools { namespace ClangTools {
namespace Internal { namespace Internal {
@@ -65,7 +64,7 @@ DiagnosticMark::DiagnosticMark(const Diagnostic &diagnostic)
const QString text = createFullLocationString(diagnostic.location) const QString text = createFullLocationString(diagnostic.location)
+ ": " + ": "
+ diagnostic.description; + diagnostic.description;
QApplication::clipboard()->setText(text); Utils::setClipboardAndSelection(text);
}); });
actions << action; actions << action;

View File

@@ -251,6 +251,8 @@ QPair<FilePath, QString> getClangIncludeDirAndVersion(ClangToolRunner *runner)
void DocumentClangToolRunner::runNext() void DocumentClangToolRunner::runNext()
{ {
if (m_currentRunner)
m_currentRunner.release()->deleteLater();
m_currentRunner.reset(m_runnerCreators.isEmpty() ? nullptr : m_runnerCreators.takeFirst()()); m_currentRunner.reset(m_runnerCreators.isEmpty() ? nullptr : m_runnerCreators.takeFirst()());
if (m_currentRunner) { if (m_currentRunner) {
auto [clangIncludeDir, clangVersion] = getClangIncludeDirAndVersion(m_currentRunner.get()); auto [clangIncludeDir, clangVersion] = getClangIncludeDirAndVersion(m_currentRunner.get());
@@ -362,10 +364,7 @@ void DocumentClangToolRunner::cancel()
if (m_projectSettingsUpdate) if (m_projectSettingsUpdate)
disconnect(m_projectSettingsUpdate); disconnect(m_projectSettingsUpdate);
m_runnerCreators.clear(); m_runnerCreators.clear();
if (m_currentRunner) { m_currentRunner.reset(nullptr);
m_currentRunner->disconnect(this);
m_currentRunner.reset(nullptr);
}
} }
bool DocumentClangToolRunner::isSuppressed(const Diagnostic &diagnostic) const bool DocumentClangToolRunner::isSuppressed(const Diagnostic &diagnostic) const

View File

@@ -63,7 +63,7 @@ static QString runExecutable(const Utils::CommandLine &commandLine, QueryFailMod
return {}; return {};
} }
return cpp.stdOut(); return cpp.cleanedStdOut();
} }
static QStringList queryClangTidyChecks(const FilePath &executable, static QStringList queryClangTidyChecks(const FilePath &executable,

View File

@@ -1676,8 +1676,8 @@ ClearCasePluginPrivate::runCleartool(const FilePath &workingDir,
response.error = proc.result() != ProcessResult::FinishedWithSuccess; response.error = proc.result() != ProcessResult::FinishedWithSuccess;
if (response.error) if (response.error)
response.message = proc.exitMessage(); response.message = proc.exitMessage();
response.stdErr = proc.stdErr(); response.stdErr = proc.cleanedStdErr();
response.stdOut = proc.stdOut(); response.stdOut = proc.cleanedStdOut();
return response; return response;
} }

View File

@@ -280,19 +280,19 @@ TextEditor::Keywords CMakeTool::keywords()
QtcProcess proc; QtcProcess proc;
runCMake(proc, {"--help-command-list"}, 5); runCMake(proc, {"--help-command-list"}, 5);
if (proc.result() == ProcessResult::FinishedWithSuccess) 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); runCMake(proc, {"--help-commands"}, 5);
if (proc.result() == ProcessResult::FinishedWithSuccess) if (proc.result() == ProcessResult::FinishedWithSuccess)
parseFunctionDetailsOutput(proc.stdOut()); parseFunctionDetailsOutput(proc.cleanedStdOut());
runCMake(proc, {"--help-property-list"}, 5); runCMake(proc, {"--help-property-list"}, 5);
if (proc.result() == ProcessResult::FinishedWithSuccess) 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); runCMake(proc, {"--help-variable-list"}, 5);
if (proc.result() == ProcessResult::FinishedWithSuccess) { 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); m_introspection->m_variables = Utils::filteredUnique(m_introspection->m_variables);
Utils::sort(m_introspection->m_variables); Utils::sort(m_introspection->m_variables);
} }
@@ -523,7 +523,7 @@ void CMakeTool::fetchFromCapabilities() const
if (cmake.result() == ProcessResult::FinishedWithSuccess) { if (cmake.result() == ProcessResult::FinishedWithSuccess) {
m_introspection->m_didRun = true; m_introspection->m_didRun = true;
parseFromCapabilities(cmake.stdOut()); parseFromCapabilities(cmake.cleanedStdOut());
} else { } else {
qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << cmake.allOutput() << cmake.error(); qCCritical(cmakeToolLog) << "Fetching capabilities failed: " << cmake.allOutput() << cmake.error();
m_introspection->m_didRun = false; m_introspection->m_didRun = false;

View File

@@ -402,18 +402,18 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
const bool hasPchSource = anyOf(sources, [buildDirectory](const QString &path) { const bool hasPchSource = anyOf(sources, [buildDirectory](const QString &path) {
return isPchFile(buildDirectory, FilePath::fromString(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) { for (const SourceInfo &si : t.sources) {
if (si.isGenerated) if (si.isGenerated)
continue; continue;
const auto mimeTypes = Utils::mimeTypesForFileName(si.path); const auto mimeTypes = Utils::mimeTypesForFileName(si.path);
for (auto mime : mimeTypes) for (const auto &mime : mimeTypes)
if (mime.name() == headerMimeType) if (mime.name() == headerMimeType)
sources.push_back(sourceDir.absoluteFilePath(si.path)); sources.push_back(sourceDir.absoluteFilePath(si.path));
} }
@@ -421,8 +421,14 @@ RawProjectParts generateRawProjectParts(const PreprocessedData &input,
// Set project files except pch files // Set project files except pch files
rpp.setFiles(Utils::filtered(sources, [buildDirectory](const QString &path) { 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 precompiled_header
= FilePath::fromString(findOrDefault(t.sources, [&ending](const SourceInfo &si) { = FilePath::fromString(findOrDefault(t.sources, [&ending](const SourceInfo &si) {

View File

@@ -36,6 +36,7 @@
#include <projectexplorer/toolchain.h> #include <projectexplorer/toolchain.h>
#include <projectexplorer/toolchainmanager.h> #include <projectexplorer/toolchainmanager.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/hostosinfo.h>
#include <QtTest> #include <QtTest>
@@ -239,13 +240,15 @@ void CompilationDatabaseTests::testFilterCommand()
"SemaCodeComplete"); "SemaCodeComplete");
testData.getFilteredFlags(); testData.getFilteredFlags();
QCOMPARE(testData.flags, if (Utils::HostOsInfo::isWindowsHost()) {
(QStringList{"/Zc:inline", "/Zc:strictStrings", "/Zc:rvalueCast", "/Zi"})); QCOMPARE(testData.flags,
QCOMPARE(testData.headerPaths, (QStringList{"/Zc:inline", "/Zc:strictStrings", "/Zc:rvalueCast", "/Zi"}));
toUserHeaderPaths(QStringList{"C:/build-qt_llvm-msvc2017_64bit-Debug/tools\\clang\\lib\\Sema"})); QCOMPARE(testData.headerPaths,
QCOMPARE(testData.macros, (Macros{{"UNICODE", "1"}, {"_HAS_EXCEPTIONS", "0"}, {"WIN32", "1"}, toUserHeaderPaths(QStringList{"C:/build-qt_llvm-msvc2017_64bit-Debug/tools\\clang\\lib\\Sema"}));
{"_WINDOWS", "1"}})); QCOMPARE(testData.macros, (Macros{{"UNICODE", "1"}, {"_HAS_EXCEPTIONS", "0"}, {"WIN32", "1"},
QCOMPARE(testData.fileKind, CppEditor::ProjectFile::Kind::CXXSource); {"_WINDOWS", "1"}}));
QCOMPARE(testData.fileKind, CppEditor::ProjectFile::Kind::CXXSource);
}
} }
void CompilationDatabaseTests::testFileKindDifferentFromExtension() void CompilationDatabaseTests::testFileKindDifferentFromExtension()

View File

@@ -206,7 +206,7 @@ void filteredFlags(const QString &fileName,
} }
// Skip all remaining Windows flags except feature flags. // Skip all remaining Windows flags except feature flags.
if (flag.startsWith("/") && !flag.startsWith("/Z")) if (Utils::HostOsInfo::isWindowsHost() && flag.startsWith("/") && !flag.startsWith("/Z"))
continue; continue;
filtered.push_back(flag); filtered.push_back(flag);

View File

@@ -830,8 +830,7 @@ FilePath DocumentManager::getSaveFileName(const QString &title, const FilePath &
bool repeat; bool repeat;
do { do {
repeat = false; repeat = false;
filePath = FileUtils::getSaveFilePath(nullptr, title, path, filter, selectedFilter, filePath = FileUtils::getSaveFilePath(nullptr, title, path, filter, selectedFilter);
QFileDialog::DontConfirmOverwrite);
if (!filePath.isEmpty()) { if (!filePath.isEmpty()) {
// If the selected filter is All Files (*) we leave the name exactly as the user // 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 // 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; suffixOk = true;
break; break;
} }
if (!suffixOk && !suffixes.isEmpty()) if (!suffixOk && !suffixes.isEmpty()) {
filePath = filePath.stringAppended(suffixes.at(0)); 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); } while (repeat);
if (!filePath.isEmpty()) if (!filePath.isEmpty())

View File

@@ -132,16 +132,10 @@ void ExecuteFilter::accept(const LocatorFilterEntry &selection,
p->runHeadCommand(); p->runHeadCommand();
} }
void ExecuteFilter::finished() void ExecuteFilter::done()
{ {
QTC_ASSERT(m_process, return); QTC_ASSERT(m_process, return);
const QString commandName = headCommand(); MessageManager::writeFlashing(m_process->exitMessage());
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);
removeProcess(); removeProcess();
runHeadCommand(); runHeadCommand();
@@ -180,12 +174,6 @@ void ExecuteFilter::runHeadCommand()
m_process->setWorkingDirectory(d.workingDirectory); m_process->setWorkingDirectory(d.workingDirectory);
m_process->setCommand(d.command); m_process->setCommand(d.command);
m_process->start(); 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 = new Utils::QtcProcess;
m_process->setEnvironment(Utils::Environment::systemEnvironment()); 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::readyReadStandardOutput, this, &ExecuteFilter::readStandardOutput);
connect(m_process, &QtcProcess::readyReadStandardError, this, &ExecuteFilter::readStandardError); connect(m_process, &QtcProcess::readyReadStandardError, this, &ExecuteFilter::readStandardError);
} }
@@ -207,7 +195,7 @@ void ExecuteFilter::removeProcess()
return; return;
m_taskQueue.dequeue(); m_taskQueue.dequeue();
delete m_process; m_process->deleteLater();
m_process = nullptr; m_process = nullptr;
} }

View File

@@ -57,7 +57,7 @@ public:
QString *newText, int *selectionStart, int *selectionLength) const override; QString *newText, int *selectionStart, int *selectionLength) const override;
private: private:
void finished(); void done();
void readStandardOutput(); void readStandardOutput();
void readStandardError(); void readStandardError();
void runHeadCommand(); void runHeadCommand();

View File

@@ -28,7 +28,6 @@
#include <utils/hostosinfo.h> #include <utils/hostosinfo.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <coreplugin/messagemanager.h> #include <coreplugin/messagemanager.h>
@@ -37,11 +36,9 @@ using namespace Utils;
namespace Cppcheck { namespace Cppcheck {
namespace Internal { namespace Internal {
CppcheckRunner::CppcheckRunner(CppcheckTool &tool) : CppcheckRunner::CppcheckRunner(CppcheckTool &tool) : m_tool(tool)
m_tool(tool),
m_process(new Utils::QtcProcess(this))
{ {
if (Utils::HostOsInfo::hostOs() == Utils::OsTypeLinux) { if (HostOsInfo::hostOs() == OsTypeLinux) {
QtcProcess getConf; QtcProcess getConf;
getConf.setCommand({"getconf", {"ARG_MAX"}}); getConf.setCommand({"getconf", {"ARG_MAX"}});
getConf.start(); getConf.start();
@@ -50,17 +47,15 @@ CppcheckRunner::CppcheckRunner(CppcheckTool &tool) :
m_maxArgumentsLength = std::max(argMax.toInt(), m_maxArgumentsLength); 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_tool.parseOutputLine(line);
}); });
m_process->setStdErrLineCallback([this](const QString &line) { m_process.setStdErrLineCallback([this](const QString &line) {
m_tool.parseErrorLine(line); m_tool.parseErrorLine(line);
}); });
connect(m_process, &QtcProcess::started, connect(&m_process, &QtcProcess::started, &m_tool, &CppcheckTool::startParsing);
this, &CppcheckRunner::handleStarted); connect(&m_process, &QtcProcess::done, this, &CppcheckRunner::handleDone);
connect(m_process, &QtcProcess::finished,
this, &CppcheckRunner::handleFinished);
m_queueTimer.setSingleShot(true); m_queueTimer.setSingleShot(true);
const int checkDelayInMs = 200; const int checkDelayInMs = 200;
@@ -81,18 +76,18 @@ void CppcheckRunner::reconfigure(const FilePath &binary, const QString &argument
m_arguments = arguments; m_arguments = arguments;
} }
void CppcheckRunner::addToQueue(const Utils::FilePaths &files, void CppcheckRunner::addToQueue(const FilePaths &files,
const QString &additionalArguments) const QString &additionalArguments)
{ {
Utils::FilePaths &existing = m_queue[additionalArguments]; FilePaths &existing = m_queue[additionalArguments];
if (existing.isEmpty()) { if (existing.isEmpty()) {
existing = files; existing = files;
} else { } else {
std::copy_if(files.cbegin(), files.cend(), std::back_inserter(existing), 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); stop(existing);
return; return;
} }
@@ -100,16 +95,16 @@ void CppcheckRunner::addToQueue(const Utils::FilePaths &files,
m_queueTimer.start(); m_queueTimer.start();
} }
void CppcheckRunner::stop(const Utils::FilePaths &files) void CppcheckRunner::stop(const FilePaths &files)
{ {
if (!m_isRunning) if (!m_process.isRunning())
return; return;
if (files.isEmpty() || m_currentFiles == files) 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()) if (m_queue.isEmpty())
return; return;
@@ -118,21 +113,21 @@ void CppcheckRunner::removeFromQueue(const Utils::FilePaths &files)
m_queue.clear(); m_queue.clear();
} else { } else {
for (auto it = m_queue.begin(), end = m_queue.end(); it != end;) { 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.value().removeOne(file);
it = !it.value().isEmpty() ? ++it : m_queue.erase(it); it = !it.value().isEmpty() ? ++it : m_queue.erase(it);
} }
} }
} }
const Utils::FilePaths &CppcheckRunner::currentFiles() const const FilePaths &CppcheckRunner::currentFiles() const
{ {
return m_currentFiles; return m_currentFiles;
} }
QString CppcheckRunner::currentCommand() const QString CppcheckRunner::currentCommand() const
{ {
return m_process->commandLine().toUserOutput(); return m_process.commandLine().toUserOutput();
} }
void CppcheckRunner::checkQueued() void CppcheckRunner::checkQueued()
@@ -140,7 +135,7 @@ void CppcheckRunner::checkQueued()
if (m_queue.isEmpty() || m_binary.isEmpty()) if (m_queue.isEmpty() || m_binary.isEmpty())
return; return;
Utils::FilePaths files = m_queue.begin().value(); FilePaths files = m_queue.begin().value();
QString arguments = m_arguments + ' ' + m_queue.begin().key(); QString arguments = m_arguments + ' ' + m_queue.begin().key();
m_currentFiles.clear(); m_currentFiles.clear();
int argumentsLength = arguments.length(); int argumentsLength = arguments.length();
@@ -158,30 +153,19 @@ void CppcheckRunner::checkQueued()
else else
m_queue.begin().value() = files; m_queue.begin().value() = files;
m_process->setCommand(CommandLine(m_binary, arguments, CommandLine::Raw)); m_process.setCommand(CommandLine(m_binary, arguments, CommandLine::Raw));
m_process->start(); m_process.start();
} }
void CppcheckRunner::handleStarted() void CppcheckRunner::handleDone()
{ {
if (m_isRunning) if (m_process.result() == ProcessResult::FinishedWithSuccess)
return;
m_isRunning = true;
m_tool.startParsing();
}
void CppcheckRunner::handleFinished()
{
if (m_process->error() != QProcess::FailedToStart) {
m_tool.finishParsing(); m_tool.finishParsing();
} else { else
const QString message = tr("Cppcheck failed to start: \"%1\".").arg(currentCommand()); Core::MessageManager::writeSilently(m_process.exitMessage());
Core::MessageManager::writeSilently(message);
}
m_currentFiles.clear(); m_currentFiles.clear();
m_process->close(); m_process.close();
m_isRunning = false;
if (!m_queue.isEmpty()) if (!m_queue.isEmpty())
checkQueued(); checkQueued();

View File

@@ -26,12 +26,11 @@
#pragma once #pragma once
#include <utils/filepath.h> #include <utils/filepath.h>
#include <utils/qtcprocess.h>
#include <QHash> #include <QHash>
#include <QTimer> #include <QTimer>
namespace Utils { class QtcProcess; }
namespace Cppcheck { namespace Cppcheck {
namespace Internal { namespace Internal {
@@ -58,18 +57,16 @@ private:
void checkQueued(); void checkQueued();
void readOutput(); void readOutput();
void readError(); void readError();
void handleStarted(); void handleDone();
void handleFinished();
CppcheckTool &m_tool; CppcheckTool &m_tool;
Utils::QtcProcess *m_process = nullptr; Utils::QtcProcess m_process;
Utils::FilePath m_binary; Utils::FilePath m_binary;
QString m_arguments; QString m_arguments;
QHash<QString, Utils::FilePaths> m_queue; QHash<QString, Utils::FilePaths> m_queue;
Utils::FilePaths m_currentFiles; Utils::FilePaths m_currentFiles;
QTimer m_queueTimer; QTimer m_queueTimer;
int m_maxArgumentsLength = 32767; int m_maxArgumentsLength = 32767;
bool m_isRunning = false;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -34,6 +34,7 @@
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <utils/algorithm.h> #include <utils/algorithm.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/qtcprocess.h> #include <utils/qtcprocess.h>
#include <utils/settingsutils.h> #include <utils/settingsutils.h>
@@ -81,6 +82,7 @@ static QString clangdSizeThresholdKey() { return QLatin1String("ClangdSizeThresh
static QString clangdUseGlobalSettingsKey() { return QLatin1String("useGlobalSettings"); } static QString clangdUseGlobalSettingsKey() { return QLatin1String("useGlobalSettings"); }
static QString sessionsWithOneClangdKey() { return QLatin1String("SessionsWithOneClangd"); } static QString sessionsWithOneClangdKey() { return QLatin1String("SessionsWithOneClangd"); }
static QString diagnosticConfigIdKey() { return QLatin1String("diagnosticConfigId"); } static QString diagnosticConfigIdKey() { return QLatin1String("diagnosticConfigId"); }
static QString checkedHardwareKey() { return QLatin1String("checkedHardware"); }
static FilePath g_defaultClangdFilePath; static FilePath g_defaultClangdFilePath;
static FilePath fallbackClangdFilePath() static FilePath fallbackClangdFilePath()
@@ -206,6 +208,22 @@ bool ClangdSettings::useClangd() const
return m_data.useClangd && clangdVersion() >= QVersionNumber(14); 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<quint64> totalRam = Utils::HostOsInfo::totalMemoryInstalledInBytes();
return !totalRam || *totalRam >= minRam;
}
bool ClangdSettings::haveCheckedHardwareRequirements()
{
return instance().data().haveCheckedHardwareReqirements;
}
void ClangdSettings::setDefaultClangdPath(const FilePath &filePath) void ClangdSettings::setDefaultClangdPath(const FilePath &filePath)
{ {
g_defaultClangdFilePath = filePath; g_defaultClangdFilePath = filePath;
@@ -350,8 +368,6 @@ void ClangdSettings::saveSettings()
} }
#ifdef WITH_TESTS #ifdef WITH_TESTS
void ClangdSettings::setUseClangd(bool use) { instance().m_data.useClangd = use; }
void ClangdSettings::setClangdFilePath(const FilePath &filePath) void ClangdSettings::setClangdFilePath(const FilePath &filePath)
{ {
instance().m_data.executableFilePath = filePath; instance().m_data.executableFilePath = filePath;
@@ -435,6 +451,7 @@ QVariantMap ClangdSettings::Data::toMap() const
map.insert(clangdSizeThresholdKey(), sizeThresholdInKb); map.insert(clangdSizeThresholdKey(), sizeThresholdInKb);
map.insert(sessionsWithOneClangdKey(), sessionsWithOneClangd); map.insert(sessionsWithOneClangdKey(), sessionsWithOneClangd);
map.insert(diagnosticConfigIdKey(), diagnosticConfigId.toSetting()); map.insert(diagnosticConfigIdKey(), diagnosticConfigId.toSetting());
map.insert(checkedHardwareKey(), true);
return map; return map;
} }
@@ -451,6 +468,7 @@ void ClangdSettings::Data::fromMap(const QVariantMap &map)
sessionsWithOneClangd = map.value(sessionsWithOneClangdKey()).toStringList(); sessionsWithOneClangd = map.value(sessionsWithOneClangdKey()).toStringList();
diagnosticConfigId = Id::fromSetting(map.value(diagnosticConfigIdKey(), diagnosticConfigId = Id::fromSetting(map.value(diagnosticConfigIdKey(),
initialClangDiagnosticConfigId().toSetting())); initialClangDiagnosticConfigId().toSetting()));
haveCheckedHardwareReqirements = map.value(checkedHardwareKey(), false).toBool();
} }
} // namespace CppEditor } // namespace CppEditor

View File

@@ -111,7 +111,8 @@ public:
&& s1.autoIncludeHeaders == s2.autoIncludeHeaders && s1.autoIncludeHeaders == s2.autoIncludeHeaders
&& s1.documentUpdateThreshold == s2.documentUpdateThreshold && s1.documentUpdateThreshold == s2.documentUpdateThreshold
&& s1.sizeThresholdEnabled == s2.sizeThresholdEnabled && 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); } friend bool operator!=(const Data &s1, const Data &s2) { return !(s1 == s2); }
@@ -126,12 +127,17 @@ public:
bool enableIndexing = true; bool enableIndexing = true;
bool autoIncludeHeaders = false; bool autoIncludeHeaders = false;
bool sizeThresholdEnabled = false; bool sizeThresholdEnabled = false;
bool haveCheckedHardwareReqirements = false;
}; };
ClangdSettings(const Data &data) : m_data(data) {} ClangdSettings(const Data &data) : m_data(data) {}
static ClangdSettings &instance(); static ClangdSettings &instance();
bool useClangd() const; bool useClangd() const;
static void setUseClangd(bool use);
static bool hardwareFulfillsRequirements();
static bool haveCheckedHardwareRequirements();
static void setDefaultClangdPath(const Utils::FilePath &filePath); static void setDefaultClangdPath(const Utils::FilePath &filePath);
static void setCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs); static void setCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs);
@@ -159,7 +165,6 @@ public:
static Utils::FilePath clangdUserConfigFilePath(); static Utils::FilePath clangdUserConfigFilePath();
#ifdef WITH_TESTS #ifdef WITH_TESTS
static void setUseClangd(bool use);
static void setClangdFilePath(const Utils::FilePath &filePath); static void setClangdFilePath(const Utils::FilePath &filePath);
#endif #endif

View File

@@ -135,6 +135,12 @@ static const char *DEFAULT_CODE_STYLE_SNIPPETS[]
"private:\n" "private:\n"
" int _a;\n" " int _a;\n"
" };\n" " };\n"
"enum class E\n"
"{\n"
" V1,\n"
" V2,\n"
" V3\n"
"};\n"
"}\n" "}\n"
"}\n", "}\n",
"#include \"bar.h\"\n" "#include \"bar.h\"\n"

View File

@@ -50,7 +50,9 @@
#include <utils/minimizableinfobars.h> #include <utils/minimizableinfobars.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/runextensions.h> #include <utils/runextensions.h>
#include <utils/utilsicons.h>
#include <QApplication>
#include <QTextDocument> #include <QTextDocument>
const char NO_PROJECT_CONFIGURATION[] = "NoProject"; const char NO_PROJECT_CONFIGURATION[] = "NoProject";
@@ -121,6 +123,9 @@ CppEditorDocument::CppEditorDocument()
connect(this, &IDocument::filePathChanged, connect(this, &IDocument::filePathChanged,
this, &CppEditorDocument::onFilePathChanged); this, &CppEditorDocument::onFilePathChanged);
connect(mm(), &CppModelManager::diagnosticsChanged,
this, &CppEditorDocument::onDiagnosticsChanged);
connect(&m_parseContextModel, &ParseContextModel::preferredParseContextChanged, connect(&m_parseContextModel, &ParseContextModel::preferredParseContextChanged,
this, &CppEditorDocument::reparseWithPreferredParseContext); this, &CppEditorDocument::reparseWithPreferredParseContext);
@@ -483,5 +488,51 @@ bool CppEditorDocument::save(QString *errorString, const FilePath &filePath, boo
return TextEditor::TextDocument::save(errorString, filePath, autoSave); 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 Internal
} // namespace CppEditor } // namespace CppEditor

View File

@@ -94,6 +94,8 @@ private:
void onAboutToReload(); void onAboutToReload();
void onReloadFinished(); void onReloadFinished();
void onDiagnosticsChanged(const QString &fileName, const QString &kind);
void reparseWithPreferredParseContext(const QString &id); void reparseWithPreferredParseContext(const QString &id);

View File

@@ -201,6 +201,8 @@ public:
std::unique_ptr<Core::ILocatorFilter> m_functionsFilter; std::unique_ptr<Core::ILocatorFilter> m_functionsFilter;
std::unique_ptr<Core::IFindFilter> m_symbolsFindFilter; std::unique_ptr<Core::IFindFilter> m_symbolsFindFilter;
std::unique_ptr<Core::ILocatorFilter> m_currentDocumentFilter; std::unique_ptr<Core::ILocatorFilter> m_currentDocumentFilter;
QList<Document::DiagnosticMessage> m_diagnosticMessages;
}; };
} // namespace Internal } // namespace Internal
@@ -1704,4 +1706,18 @@ QThreadPool *CppModelManager::sharedThreadPool()
return &d->m_threadPool; return &d->m_threadPool;
} }
bool CppModelManager::setExtraDiagnostics(const QString &fileName,
const QString &kind,
const QList<Document::DiagnosticMessage> &diagnostics)
{
d->m_diagnosticMessages = diagnostics;
emit diagnosticsChanged(fileName, kind);
return true;
}
const QList<Document::DiagnosticMessage> CppModelManager::diagnosticMessages()
{
return d->m_diagnosticMessages;
}
} // namespace CppEditor } // namespace CppEditor

View File

@@ -104,6 +104,12 @@ public:
QByteArray codeModelConfiguration() const; QByteArray codeModelConfiguration() const;
CppLocatorData *locatorData() const; CppLocatorData *locatorData() const;
bool setExtraDiagnostics(const QString &fileName,
const QString &kind,
const QList<Document::DiagnosticMessage> &diagnostics) override;
const QList<Document::DiagnosticMessage> diagnosticMessages();
QList<ProjectInfo::ConstPtr> projectInfos() const; QList<ProjectInfo::ConstPtr> projectInfos() const;
ProjectInfo::ConstPtr projectInfo(ProjectExplorer::Project *project) const; ProjectInfo::ConstPtr projectInfo(ProjectExplorer::Project *project) const;
QFuture<void> updateProjectInfo(const ProjectInfo::ConstPtr &newProjectInfo, QFuture<void> updateProjectInfo(const ProjectInfo::ConstPtr &newProjectInfo,
@@ -256,6 +262,8 @@ signals:
void abstractEditorSupportRemoved(const QString &filePath); void abstractEditorSupportRemoved(const QString &filePath);
void fallbackProjectPartUpdated(); void fallbackProjectPartUpdated();
void diagnosticsChanged(const QString &fileName, const QString &kind);
public slots: public slots:
void updateModifiedSourceFiles(); void updateModifiedSourceFiles();
void GC(); void GC();

View File

@@ -87,7 +87,8 @@ const QVector<ProjectPart::ConstPtr> ProjectInfoGenerator::createProjectParts(
QVector<ProjectPart::ConstPtr> result; QVector<ProjectPart::ConstPtr> result;
ProjectFileCategorizer cat(rawProjectPart.displayName, ProjectFileCategorizer cat(rawProjectPart.displayName,
rawProjectPart.files, rawProjectPart.files,
rawProjectPart.fileIsActive); rawProjectPart.fileIsActive,
rawProjectPart.getMimeType);
if (!cat.hasParts()) if (!cat.hasParts())
return result; return result;

View File

@@ -1449,8 +1449,8 @@ CvsResponse CvsPluginPrivate::runCvs(const FilePath &workingDirectory,
command.runCommand(proc, {executable, m_settings.addOptions(arguments)}); command.runCommand(proc, {executable, m_settings.addOptions(arguments)});
response.result = CvsResponse::OtherError; response.result = CvsResponse::OtherError;
response.stdErr = proc.stdErr(); response.stdErr = proc.cleanedStdErr();
response.stdOut = proc.stdOut(); response.stdOut = proc.cleanedStdOut();
switch (proc.result()) { switch (proc.result()) {
case ProcessResult::FinishedWithSuccess: case ProcessResult::FinishedWithSuccess:
response.result = CvsResponse::Ok; response.result = CvsResponse::Ok;

View File

@@ -30,12 +30,12 @@
#include <coreplugin/editormanager/editormanager.h> #include <coreplugin/editormanager/editormanager.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/stringutils.h>
#include <utils/utilsicons.h> #include <utils/utilsicons.h>
#include <QApplication>
#include <QAbstractTextDocumentLayout> #include <QAbstractTextDocumentLayout>
#include <QAction> #include <QAction>
#include <QApplication>
#include <QClipboard>
#include <QContextMenuEvent> #include <QContextMenuEvent>
#include <QFileInfo> #include <QFileInfo>
#include <QHeaderView> #include <QHeaderView>
@@ -54,12 +54,12 @@ DetailedErrorView::DetailedErrorView(QWidget *parent) :
m_copyAction->setIcon(Utils::Icons::COPY.icon()); m_copyAction->setIcon(Utils::Icons::COPY.icon());
m_copyAction->setShortcut(QKeySequence::Copy); m_copyAction->setShortcut(QKeySequence::Copy);
m_copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); m_copyAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
connect(m_copyAction, &QAction::triggered, [this] { connect(m_copyAction, &QAction::triggered, this, [this] {
const QModelIndexList selectedRows = selectionModel()->selectedRows(); const QModelIndexList selectedRows = selectionModel()->selectedRows();
QStringList data; QStringList data;
for (const QModelIndex &index : selectedRows) for (const QModelIndex &index : selectedRows)
data << model()->data(index, FullTextRole).toString(); data << model()->data(index, FullTextRole).toString();
QApplication::clipboard()->setText(data.join('\n')); Utils::setClipboardAndSelection(data.join('\n'));
}); });
connect(this, &QAbstractItemView::clicked, [](const QModelIndex &index) { connect(this, &QAbstractItemView::clicked, [](const QModelIndex &index) {
if (index.column() == LocationColumn) { if (index.column() == LocationColumn) {

Some files were not shown because too many files have changed in this diff Show More