Merge remote-tracking branch 'origin/6.0'

Change-Id: Ic6f91a71dd7d540eb9b6c27ba5ef9931583566b5
This commit is contained in:
Eike Ziller
2021-10-05 09:52:55 +02:00
35 changed files with 564 additions and 181 deletions

View File

@@ -4,7 +4,7 @@ on: [push, pull_request]
env: env:
QT_VERSION: 5.15.2 QT_VERSION: 5.15.2
CLANG_VERSION: 120 CLANG_VERSION: 130
ELFUTILS_VERSION: 0.175 ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.21.1 CMAKE_VERSION: 3.21.1
NINJA_VERSION: 1.10.2 NINJA_VERSION: 1.10.2
@@ -286,9 +286,9 @@ jobs:
set(libclang "libclang-release_${clang_version}-based-windows-vs2019_32.7z") set(libclang "libclang-release_${clang_version}-based-windows-vs2019_32.7z")
endif() endif()
elseif ("${{ runner.os }}" STREQUAL "Linux") elseif ("${{ runner.os }}" STREQUAL "Linux")
set(libclang "libclang-release_${clang_version}-based-linux-Ubuntu18.04-gcc9.3-x86_64.7z") set(libclang "libclang-release_${clang_version}-based-linux-Ubuntu20.04-gcc9.3-x86_64.7z")
elseif ("${{ runner.os }}" STREQUAL "macOS") elseif ("${{ runner.os }}" STREQUAL "macOS")
set(libclang "libclang-release_${clang_version}-based-mac.7z") set(libclang "libclang-release_${clang_version}-based-macos-universal.7z")
endif() endif()
set(libclang_url "https://\${qt_mirror}/development_releases/prebuilt/libclang/${libclang}") set(libclang_url "https://\${qt_mirror}/development_releases/prebuilt/libclang/${libclang}")

View File

@@ -57,7 +57,8 @@ else()
find_package(Qt6 CONFIG ${__arguments} ${Qt5_FIND_COMPONENTS}) find_package(Qt6 CONFIG ${__arguments} ${Qt5_FIND_COMPONENTS})
endif() endif()
foreach(comp IN LISTS Qt5_FIND_COMPONENTS) set(__additional_imported_components ATSPI2_nolink) # Work around QTBUG-97023
foreach(comp IN LISTS Qt5_FIND_COMPONENTS __additional_imported_components)
if(TARGET Qt6::${comp}) if(TARGET Qt6::${comp})
if (NOT TARGET Qt5::${comp}) if (NOT TARGET Qt5::${comp})
set_property(TARGET Qt6::${comp} PROPERTY IMPORTED_GLOBAL TRUE) set_property(TARGET Qt6::${comp} PROPERTY IMPORTED_GLOBAL TRUE)

View File

@@ -7,7 +7,7 @@ instructions:
variableValue: "RelWithDebInfo" variableValue: "RelWithDebInfo"
- 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.2/6.2.0-rc-released/" variableValue: "http://ci-files02-hki.intra.qt.io/packages/jenkins/archive/qt/6.2/6.2.0-final-released/"
- 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

@@ -1075,6 +1075,20 @@ SecondColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
spacing: 0 spacing: 0
Connections {
target: ceMode
function onActivated() {
spinBox.readValue()
}
}
Connections {
target: modelNodeBackend
function onSelectionChanged() {
spinBox.readValue()
}
}
GradientPropertySpinBox { GradientPropertySpinBox {
id: spinBox id: spinBox
implicitWidth: StudioTheme.Values.controlGap implicitWidth: StudioTheme.Values.controlGap

View File

@@ -45,6 +45,10 @@ Item {
onFocusChanged: restoreCursor() onFocusChanged: restoreCursor()
function readValue() {
spinBox.realValue = gradientLine.model.readGradientProperty(wrapper.propertyName)
}
StudioControls.RealSpinBox { StudioControls.RealSpinBox {
id: spinBox id: spinBox
@@ -56,9 +60,7 @@ Item {
realStepSize: 1 realStepSize: 1
decimals: 0 decimals: 0
Component.onCompleted: { Component.onCompleted: wrapper.readValue()
spinBox.realValue = gradientLine.model.readGradientProperty(wrapper.propertyName)
}
onCompressedRealValueModified: { onCompressedRealValueModified: {
gradientLine.model.setGradientProperty(wrapper.propertyName, spinBox.realValue) gradientLine.model.setGradientProperty(wrapper.propertyName, spinBox.realValue)
} }

View File

@@ -494,6 +494,11 @@ int main(int argc, char **argv)
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar); QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
} }
if (Utils::HostOsInfo::isRunningUnderRosetta()) {
// work around QTBUG-97085: QRegularExpression jitting is not reentrant under Rosetta
qputenv("QT_ENABLE_REGEXP_JIT", "0");
}
Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX"); Utils::TemporaryDirectory::setMasterTemporaryDirectory(QDir::tempPath() + "/" + Core::Constants::IDE_CASED_ID + "-XXXXXX");
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS

View File

@@ -1747,7 +1747,7 @@ bool Check::visit(CallExpression *ast)
static const QStringList colorFunctions = {"lighter", "darker", "rgba", "tint", "hsla", "hsva"}; static const QStringList colorFunctions = {"lighter", "darker", "rgba", "tint", "hsla", "hsva"};
static const QStringList qtFunction = {"point", "rect", "size", "vector2d", "vector3d", "vector4d", "quaternion" "matrix4x4", "formatDate", static const QStringList qtFunction = {"point", "rect", "size", "vector2d", "vector3d", "vector4d", "quaternion" "matrix4x4", "formatDate",
"formatDateTime", "formatTime"}; "formatDateTime", "formatTime", "resolvedUrl"};
const bool whiteListedFunction = translationFunctions.contains(name) || whiteListedFunctions.contains(name) || colorFunctions.contains(name) || qtFunction.contains(name); const bool whiteListedFunction = translationFunctions.contains(name) || whiteListedFunctions.contains(name) || colorFunctions.contains(name) || qtFunction.contains(name);

View File

@@ -136,8 +136,10 @@ void Environment::setupEnglishOutput()
set("LANGUAGE", "en_US:en"); set("LANGUAGE", "en_US:en");
} }
FilePath Environment::searchInDirectory(const QStringList &execs, const FilePath &directory, static FilePath searchInDirectory(const Environment &env,
QSet<FilePath> &alreadyChecked) const QStringList &execs,
const FilePath &directory,
QSet<FilePath> &alreadyChecked)
{ {
const int checkedCount = alreadyChecked.count(); const int checkedCount = alreadyChecked.count();
alreadyChecked.insert(directory); alreadyChecked.insert(directory);
@@ -199,17 +201,19 @@ QString Environment::expandedValueForKey(const QString &key) const
return expandVariables(value(key)); return expandVariables(value(key));
} }
FilePath Environment::searchInPath(const QString &executable, static FilePath searchInDirectoriesHelper(const Environment &env,
const FilePaths &additionalDirs, const QString &executable,
const PathFilter &func) const const FilePaths &dirs,
const Environment::PathFilter &func,
bool usePath)
{ {
if (executable.isEmpty()) if (executable.isEmpty())
return FilePath(); return FilePath();
const QString exec = QDir::cleanPath(expandVariables(executable)); const QString exec = QDir::cleanPath(env.expandVariables(executable));
const QFileInfo fi(exec); const QFileInfo fi(exec);
const QStringList execs = appendExeExtensions(exec); const QStringList execs = env.appendExeExtensions(exec);
if (fi.isAbsolute()) { if (fi.isAbsolute()) {
for (const QString &path : execs) { for (const QString &path : execs) {
@@ -221,23 +225,38 @@ FilePath Environment::searchInPath(const QString &executable,
} }
QSet<FilePath> alreadyChecked; QSet<FilePath> alreadyChecked;
for (const FilePath &dir : additionalDirs) { for (const FilePath &dir : dirs) {
FilePath tmp = searchInDirectory(execs, dir, alreadyChecked); FilePath tmp = searchInDirectory(env, execs, dir, alreadyChecked);
if (!tmp.isEmpty() && (!func || func(tmp))) if (!tmp.isEmpty() && (!func || func(tmp)))
return tmp; return tmp;
} }
if (executable.contains('/')) if (usePath) {
return FilePath(); if (executable.contains('/'))
return FilePath();
for (const FilePath &p : path()) { for (const FilePath &p : env.path()) {
FilePath tmp = searchInDirectory(execs, p, alreadyChecked); FilePath tmp = searchInDirectory(env, execs, p, alreadyChecked);
if (!tmp.isEmpty() && (!func || func(tmp))) if (!tmp.isEmpty() && (!func || func(tmp)))
return tmp; return tmp;
}
} }
return FilePath(); return FilePath();
} }
FilePath Environment::searchInDirectories(const QString &executable,
const FilePaths &dirs) const
{
return searchInDirectoriesHelper(*this, executable, dirs, {}, false);
}
FilePath Environment::searchInPath(const QString &executable,
const FilePaths &additionalDirs,
const PathFilter &func) const
{
return searchInDirectoriesHelper(*this, executable, additionalDirs, func, true);
}
FilePaths Environment::findAllInPath(const QString &executable, FilePaths Environment::findAllInPath(const QString &executable,
const FilePaths &additionalDirs, const FilePaths &additionalDirs,
const Environment::PathFilter &func) const const Environment::PathFilter &func) const
@@ -262,14 +281,14 @@ FilePaths Environment::findAllInPath(const QString &executable,
QSet<FilePath> result; QSet<FilePath> result;
QSet<FilePath> alreadyChecked; QSet<FilePath> alreadyChecked;
for (const FilePath &dir : additionalDirs) { for (const FilePath &dir : additionalDirs) {
FilePath tmp = searchInDirectory(execs, dir, alreadyChecked); FilePath tmp = searchInDirectory(*this, execs, dir, alreadyChecked);
if (!tmp.isEmpty() && (!func || func(tmp))) if (!tmp.isEmpty() && (!func || func(tmp)))
result << tmp; result << tmp;
} }
if (!executable.contains('/')) { if (!executable.contains('/')) {
for (const FilePath &p : path()) { for (const FilePath &p : path()) {
FilePath tmp = searchInDirectory(execs, p, alreadyChecked); FilePath tmp = searchInDirectory(*this, execs, p, alreadyChecked);
if (!tmp.isEmpty() && (!func || func(tmp))) if (!tmp.isEmpty() && (!func || func(tmp)))
result << tmp; result << tmp;
} }

View File

@@ -63,6 +63,8 @@ public:
FilePath searchInPath(const QString &executable, FilePath searchInPath(const QString &executable,
const FilePaths &additionalDirs = FilePaths(), const FilePaths &additionalDirs = FilePaths(),
const PathFilter &func = PathFilter()) const; const PathFilter &func = PathFilter()) const;
FilePath searchInDirectories(const QString &executable,
const FilePaths &dirs) const;
FilePaths findAllInPath(const QString &executable, FilePaths findAllInPath(const QString &executable,
const FilePaths &additionalDirs = FilePaths(), const FilePaths &additionalDirs = FilePaths(),
const PathFilter &func = PathFilter()) const; const PathFilter &func = PathFilter()) const;
@@ -80,10 +82,6 @@ public:
static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!! static void modifySystemEnvironment(const EnvironmentItems &list); // use with care!!!
static void setSystemEnvironment(const Environment &environment); // don't use at all!!! static void setSystemEnvironment(const Environment &environment); // don't use at all!!!
private:
static FilePath searchInDirectory(const QStringList &execs, const FilePath &directory,
QSet<FilePath> &alreadyChecked);
}; };
class QTCREATOR_UTILS_EXPORT EnvironmentChange final class QTCREATOR_UTILS_EXPORT EnvironmentChange final

View File

@@ -1208,7 +1208,7 @@ FilePath FilePath::searchInDirectories(const FilePaths &dirs) const
QTC_ASSERT(s_deviceHooks.searchInPath, return {}); QTC_ASSERT(s_deviceHooks.searchInPath, return {});
return s_deviceHooks.searchInPath(*this, dirs); return s_deviceHooks.searchInPath(*this, dirs);
} }
return Environment::systemEnvironment().searchInPath(path(), dirs); return Environment::systemEnvironment().searchInDirectories(path(), dirs);
} }
FilePath FilePath::searchInPath(const QList<FilePath> &additionalDirs) const FilePath FilePath::searchInPath(const QList<FilePath> &additionalDirs) const

View File

@@ -69,8 +69,8 @@ public:
void updateDeviceFromUi() final {} void updateDeviceFromUi() final {}
static QString dialogTitle(); static QString dialogTitle();
static bool criticalDialog(const QString &error); static bool criticalDialog(const QString &error, QWidget *parent = nullptr);
static bool questionDialog(const QString &question); static bool questionDialog(const QString &question, QWidget *parent = nullptr);
}; };
AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device) AndroidDeviceWidget::AndroidDeviceWidget(const IDevice::Ptr &device)
@@ -114,10 +114,10 @@ QString AndroidDeviceWidget::dialogTitle()
return tr("Android Device Manager"); return tr("Android Device Manager");
} }
bool AndroidDeviceWidget::criticalDialog(const QString &error) bool AndroidDeviceWidget::criticalDialog(const QString &error, QWidget *parent)
{ {
qCDebug(androidDeviceLog) << error; qCDebug(androidDeviceLog) << error;
QMessageBox box(Core::ICore::dialogParent()); QMessageBox box(parent ? parent : Core::ICore::dialogParent());
box.QDialog::setWindowTitle(dialogTitle()); box.QDialog::setWindowTitle(dialogTitle());
box.setText(error); box.setText(error);
box.setIcon(QMessageBox::Critical); box.setIcon(QMessageBox::Critical);
@@ -125,9 +125,9 @@ bool AndroidDeviceWidget::criticalDialog(const QString &error)
return box.exec(); return box.exec();
} }
bool AndroidDeviceWidget::questionDialog(const QString &question) bool AndroidDeviceWidget::questionDialog(const QString &question, QWidget *parent)
{ {
QMessageBox box(Core::ICore::dialogParent()); QMessageBox box(parent ? parent : Core::ICore::dialogParent());
box.QDialog::setWindowTitle(dialogTitle()); box.QDialog::setWindowTitle(dialogTitle());
box.setText(question); box.setText(question);
box.setIcon(QMessageBox::Question); box.setIcon(QMessageBox::Question);
@@ -155,19 +155,56 @@ AndroidDevice::AndroidDevice()
AndroidDeviceManager::instance()->updateDevicesListOnce(); AndroidDeviceManager::instance()->updateDevicesListOnce();
}}); }});
addDeviceAction({tr("Start AVD"), [](const IDevice::Ptr &device, QWidget *parent) { addEmulatorActionsIfNotFound();
if (device->machineType() == IDevice::Emulator) }
AndroidDeviceManager::instance()->startAvd(device);
}});
addDeviceAction({tr("Erase AVD"), [](const IDevice::Ptr &device, QWidget *parent) { void AndroidDevice::addEmulatorActionsIfNotFound()
if (device->machineType() == IDevice::Emulator) {
AndroidDeviceManager::instance()->eraseAvd(device); static const QString startAvdAction = tr("Start AVD");
}}); static const QString eraseAvdAction = tr("Erase AVD");
static const QString avdArgumentsAction = tr("AVD Arguments");
addDeviceAction({tr("AVD Arguments"), [](const IDevice::Ptr &device, QWidget *parent) { bool hasStartAction = false;
AndroidDeviceManager::instance()->setEmulatorArguments(); bool hasEraseAction = false;
}}); bool hasAvdArgumentsAction = false;
for (const DeviceAction &item : deviceActions()) {
if (item.display == startAvdAction)
hasStartAction = true;
else if (item.display == eraseAvdAction)
hasEraseAction = true;
else if (item.display == avdArgumentsAction)
hasAvdArgumentsAction = true;
}
if (machineType() == Emulator) {
if (!hasStartAction) {
addDeviceAction({startAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
AndroidDeviceManager::instance()->startAvd(device, parent);
}});
}
if (!hasEraseAction) {
addDeviceAction({eraseAvdAction, [](const IDevice::Ptr &device, QWidget *parent) {
AndroidDeviceManager::instance()->eraseAvd(device, parent);
}});
}
if (!hasAvdArgumentsAction) {
addDeviceAction({avdArgumentsAction, [](const IDevice::Ptr &device, QWidget *parent) {
Q_UNUSED(device)
AndroidDeviceManager::instance()->setEmulatorArguments(parent);
}});
}
}
}
void AndroidDevice::fromMap(const QVariantMap &map)
{
IDevice::fromMap(map);
// Add Actions for Emulator is not added already.
// This is needed because actions for Emulators and physical devices are not the same.
addEmulatorActionsIfNotFound();
} }
IDevice::Ptr AndroidDevice::create() IDevice::Ptr AndroidDevice::create()
@@ -407,8 +444,9 @@ void AndroidDeviceManager::updateDevicesListOnce()
} }
} }
void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device) void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent)
{ {
Q_UNUSED(parent)
const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.data()); const AndroidDevice *androidDev = static_cast<const AndroidDevice *>(device.data());
const QString name = androidDev->avdName(); const QString name = androidDev->avdName();
qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name)); qCDebug(androidDeviceLog, "Starting Android AVD id \"%s\".", qPrintable(name));
@@ -422,7 +460,7 @@ void AndroidDeviceManager::startAvd(const ProjectExplorer::IDevice::Ptr &device)
}); });
} }
void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device) void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device, QWidget *parent)
{ {
if (device.isNull()) if (device.isNull())
return; return;
@@ -432,7 +470,7 @@ void AndroidDeviceManager::eraseAvd(const IDevice::Ptr &device)
const QString name = static_cast<const AndroidDevice *>(device.data())->avdName(); const QString name = static_cast<const AndroidDevice *>(device.data())->avdName();
const QString question = tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name); const QString question = tr("Erase the Android AVD \"%1\"?\nThis cannot be undone.").arg(name);
if (!AndroidDeviceWidget::questionDialog(question)) if (!AndroidDeviceWidget::questionDialog(question, parent))
return; return;
qCDebug(androidDeviceLog) << QString("Erasing Android AVD \"%1\" from the system.").arg(name); qCDebug(androidDeviceLog) << QString("Erasing Android AVD \"%1\" from the system.").arg(name);
@@ -460,12 +498,12 @@ void AndroidDeviceManager::handleAvdRemoved()
} }
} }
void AndroidDeviceManager::setEmulatorArguments() void AndroidDeviceManager::setEmulatorArguments(QWidget *parent)
{ {
const QString helpUrl = const QString helpUrl =
"https://developer.android.com/studio/run/emulator-commandline#startup-options"; "https://developer.android.com/studio/run/emulator-commandline#startup-options";
QInputDialog dialog(Core::ICore::dialogParent()); QInputDialog dialog(parent ? parent : Core::ICore::dialogParent());
dialog.setWindowTitle(tr("Emulator Command-line Startup Options")); dialog.setWindowTitle(tr("Emulator Command-line Startup Options"));
dialog.setLabelText(tr("Emulator command-line startup options " dialog.setLabelText(tr("Emulator command-line startup options "
"(<a href=\"%1\">Help Web Page</a>):").arg(helpUrl)); "(<a href=\"%1\">Help Web Page</a>):").arg(helpUrl));

View File

@@ -46,6 +46,8 @@ class AndroidDevice final : public ProjectExplorer::IDevice
public: public:
AndroidDevice(); AndroidDevice();
void fromMap(const QVariantMap &map) override;
static IDevice::Ptr create(); static IDevice::Ptr create();
static AndroidDeviceInfo androidDeviceInfoFromIDevice(const IDevice *dev); static AndroidDeviceInfo androidDeviceInfoFromIDevice(const IDevice *dev);
static void setAndroidDeviceInfoExtras(IDevice *dev, const AndroidDeviceInfo &info); static void setAndroidDeviceInfoExtras(IDevice *dev, const AndroidDeviceInfo &info);
@@ -74,6 +76,7 @@ public:
AndroidConfig::OpenGl openGlStatus() const; AndroidConfig::OpenGl openGlStatus() const;
private: private:
void addEmulatorActionsIfNotFound();
ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override; ProjectExplorer::IDevice::DeviceInfo deviceInformation() const override;
ProjectExplorer::IDeviceWidget *createWidget() override; ProjectExplorer::IDeviceWidget *createWidget() override;
bool canAutoDetectPorts() const override; bool canAutoDetectPorts() const override;
@@ -99,10 +102,10 @@ public:
void updateDevicesList(); void updateDevicesList();
void updateDevicesListOnce(); void updateDevicesListOnce();
void startAvd(const ProjectExplorer::IDevice::Ptr &device); void startAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
void eraseAvd(const ProjectExplorer::IDevice::Ptr &device); void eraseAvd(const ProjectExplorer::IDevice::Ptr &device, QWidget *parent = nullptr);
void setEmulatorArguments(); void setEmulatorArguments(QWidget *parent = nullptr);
private: private:
AndroidDeviceManager(QObject *parent = nullptr); AndroidDeviceManager(QObject *parent = nullptr);

View File

@@ -59,10 +59,12 @@ public:
PackageFilterModel(AndroidSdkModel* sdkModel); PackageFilterModel(AndroidSdkModel* sdkModel);
void setAcceptedPackageState(AndroidSdkPackage::PackageState state); void setAcceptedPackageState(AndroidSdkPackage::PackageState state);
void setAcceptedSearchPackage(const QString &text);
bool filterAcceptsRow(int source_row, const QModelIndex &sourceParent) const override; bool filterAcceptsRow(int source_row, const QModelIndex &sourceParent) const override;
private: private:
AndroidSdkPackage::PackageState m_packageState = AndroidSdkPackage::AnyValidState; AndroidSdkPackage::PackageState m_packageState = AndroidSdkPackage::AnyValidState;
QString m_searchText;
}; };
AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config, AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config,
@@ -129,6 +131,15 @@ AndroidSdkManagerWidget::AndroidSdkManagerWidget(AndroidConfig &config,
} }
}); });
m_ui->searchField->setPlaceholderText("Filter");
connect(m_ui->searchField, &QLineEdit::textChanged, [this, proxyModel](const QString &text) {
const bool isExpanded = m_ui->expandCheck->isChecked();
proxyModel->setAcceptedSearchPackage(text);
m_sdkModel->resetSelection();
// It is more convenient to expand the view with the results
m_ui->expandCheck->setChecked(!text.isEmpty());
});
connect(m_ui->applySelectionButton, &QPushButton::clicked, connect(m_ui->applySelectionButton, &QPushButton::clicked,
this, &AndroidSdkManagerWidget::onApplyButton); this, &AndroidSdkManagerWidget::onApplyButton);
connect(m_ui->cancelButton, &QPushButton::clicked, this, connect(m_ui->cancelButton, &QPushButton::clicked, this,
@@ -469,6 +480,12 @@ void PackageFilterModel::setAcceptedPackageState(AndroidSdkPackage::PackageState
invalidateFilter(); invalidateFilter();
} }
void PackageFilterModel::setAcceptedSearchPackage(const QString &name)
{
m_searchText = name;
invalidateFilter();
}
bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{ {
QModelIndex srcIndex = sourceModel()->index(sourceRow, 0, sourceParent); QModelIndex srcIndex = sourceModel()->index(sourceRow, 0, sourceParent);
@@ -479,19 +496,24 @@ bool PackageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour
return (AndroidSdkPackage::PackageState)i.data(AndroidSdkModel::PackageStateRole).toInt(); return (AndroidSdkPackage::PackageState)i.data(AndroidSdkModel::PackageStateRole).toInt();
}; };
auto packageFound = [this](const QModelIndex& i) {
return i.data(AndroidSdkModel::packageNameColumn).toString()
.contains(m_searchText, Qt::CaseInsensitive);
};
bool showTopLevel = false; bool showTopLevel = false;
if (!sourceParent.isValid()) { if (!sourceParent.isValid()) {
// Top Level items // Top Level items
for (int row = 0; row < sourceModel()->rowCount(srcIndex); ++row) { for (int row = 0; row < sourceModel()->rowCount(srcIndex); ++row) {
QModelIndex childIndex = sourceModel()->index(row, 0, srcIndex); QModelIndex childIndex = sourceModel()->index(row, 0, srcIndex);
if (m_packageState & packageState(childIndex)) { if ((m_packageState & packageState(childIndex) && packageFound(childIndex))) {
showTopLevel = true; showTopLevel = true;
break; break;
} }
} }
} }
return showTopLevel || (packageState(srcIndex) & m_packageState); return showTopLevel || (packageState(srcIndex) & m_packageState) && packageFound(srcIndex);
} }
OptionsDialog::OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &args, OptionsDialog::OptionsDialog(AndroidSdkManager *sdkManager, const QStringList &args,

View File

@@ -51,27 +51,7 @@
<property name="spacing"> <property name="spacing">
<number>4</number> <number>4</number>
</property> </property>
<item row="0" column="0" colspan="2"> <item row="2" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QCheckBox" name="expandCheck">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Expand All</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QTreeView" name="packagesView"> <widget class="QTreeView" name="packagesView">
<property name="indentation"> <property name="indentation">
<number>20</number> <number>20</number>
@@ -81,7 +61,7 @@
</attribute> </attribute>
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="2" column="4">
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QPushButton" name="updateInstalledButton"> <widget class="QPushButton" name="updateInstalledButton">
@@ -149,6 +129,16 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="1" column="1">
<widget class="Utils::FancyLineEdit" name="searchField"/>
</item>
<item row="1" column="2">
<widget class="QCheckBox" name="expandCheck">
<property name="text">
<string>Expand All</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="outputStack"> <widget class="QWidget" name="outputStack">
@@ -234,6 +224,13 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>Utils::FancyLineEdit</class>
<extends>QLineEdit</extends>
<header location="global">utils/fancylineedit.h</header>
</customwidget>
</customwidgets>
<tabstops> <tabstops>
<tabstop>packagesView</tabstop> <tabstop>packagesView</tabstop>
<tabstop>showAllRadio</tabstop> <tabstop>showAllRadio</tabstop>

View File

@@ -36,7 +36,7 @@ add_qtc_plugin(ClangCodeModel
clangfixitoperationsextractor.cpp clangfixitoperationsextractor.h clangfixitoperationsextractor.cpp clangfixitoperationsextractor.h
clangfollowsymbol.cpp clangfollowsymbol.h clangfollowsymbol.cpp clangfollowsymbol.h
clangfunctionhintmodel.cpp clangfunctionhintmodel.h clangfunctionhintmodel.cpp clangfunctionhintmodel.h
clanggloballocatorfilters.cpp clanggloballocatorfilters.h clangdlocatorfilters.cpp clangdlocatorfilters.h
clanghighlightingresultreporter.cpp clanghighlightingresultreporter.h clanghighlightingresultreporter.cpp clanghighlightingresultreporter.h
clanghoverhandler.cpp clanghoverhandler.h clanghoverhandler.cpp clanghoverhandler.h
clangisdiagnosticrelatedtolocation.h clangisdiagnosticrelatedtolocation.h

View File

@@ -43,7 +43,7 @@ SOURCES += \
clangoverviewmodel.cpp \ clangoverviewmodel.cpp \
clangdclient.cpp \ clangdclient.cpp \
clangdquickfixfactory.cpp \ clangdquickfixfactory.cpp \
clanggloballocatorfilters.cpp \ clangdlocatorfilters.cpp \
HEADERS += \ HEADERS += \
clangactivationsequencecontextprocessor.h \ clangactivationsequencecontextprocessor.h \
@@ -85,7 +85,7 @@ HEADERS += \
clangoverviewmodel.h \ clangoverviewmodel.h \
clangdclient.h \ clangdclient.h \
clangdquickfixfactory.h \ clangdquickfixfactory.h \
clanggloballocatorfilters.h \ clangdlocatorfilters.h \
FORMS += clangprojectsettingswidget.ui FORMS += clangprojectsettingswidget.ui

View File

@@ -64,6 +64,8 @@ QtcPlugin {
"clangdiagnosticmanager.h", "clangdiagnosticmanager.h",
"clangdiagnostictooltipwidget.cpp", "clangdiagnostictooltipwidget.cpp",
"clangdiagnostictooltipwidget.h", "clangdiagnostictooltipwidget.h",
"clangdlocatorfilters.cpp",
"clangdlocatorfilters.h",
"clangdquickfixfactory.cpp", "clangdquickfixfactory.cpp",
"clangdquickfixfactory.h", "clangdquickfixfactory.h",
"clangeditordocumentparser.cpp", "clangeditordocumentparser.cpp",
@@ -78,8 +80,6 @@ QtcPlugin {
"clangfollowsymbol.h", "clangfollowsymbol.h",
"clangfunctionhintmodel.cpp", "clangfunctionhintmodel.cpp",
"clangfunctionhintmodel.h", "clangfunctionhintmodel.h",
"clanggloballocatorfilters.cpp",
"clanggloballocatorfilters.h",
"clanghighlightingresultreporter.cpp", "clanghighlightingresultreporter.cpp",
"clanghighlightingresultreporter.h", "clanghighlightingresultreporter.h",
"clanghoverhandler.cpp", "clanghoverhandler.cpp",

View File

@@ -978,31 +978,7 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
}; };
const auto hideDiagsHandler = []{ ClangDiagnosticManager::clearTaskHubIssues(); }; const auto hideDiagsHandler = []{ ClangDiagnosticManager::clearTaskHubIssues(); };
setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler); setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler);
setSymbolStringifier(displayNameFromDocumentSymbol);
static const auto symbolStringifier = [](SymbolKind kind, const QString &name,
const QString &detail) -> QString
{
switch (kind) {
case LanguageServerProtocol::SymbolKind::Constructor:
return name + detail;
case LanguageServerProtocol::SymbolKind::Method:
case LanguageServerProtocol::SymbolKind::Function: {
const int parenOffset = detail.indexOf(" (");
if (parenOffset == -1)
return name;
return name + detail.mid(parenOffset + 1) + " -> " + detail.mid(0, parenOffset);
}
case LanguageServerProtocol::SymbolKind::Variable:
case LanguageServerProtocol::SymbolKind::Field:
case LanguageServerProtocol::SymbolKind::Constant:
if (detail.isEmpty())
return name;
return name + " -> " + detail;
default:
return name;
}
};
setSymbolStringifier(symbolStringifier);
setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens) { setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens) {
d->handleSemanticTokens(doc, tokens); d->handleSemanticTokens(doc, tokens);
}); });
@@ -1236,6 +1212,30 @@ bool ClangdClient::testingEnabled() const
return d->isTesting; return d->isTesting;
} }
QString ClangdClient::displayNameFromDocumentSymbol(SymbolKind kind, const QString &name,
const QString &detail)
{
switch (kind) {
case SymbolKind::Constructor:
return name + detail;
case SymbolKind::Method:
case LanguageServerProtocol::SymbolKind::Function: {
const int parenOffset = detail.indexOf(" (");
if (parenOffset == -1)
return name;
return name + detail.mid(parenOffset + 1) + " -> " + detail.mid(0, parenOffset);
}
case SymbolKind::Variable:
case SymbolKind::Field:
case SymbolKind::Constant:
if (detail.isEmpty())
return name;
return name + " -> " + detail;
default:
return name;
}
}
void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Location> &locations) void ClangdClient::Private::handleFindUsagesResult(quint64 key, const QList<Location> &locations)
{ {
const auto refData = runningFindUsages.find(key); const auto refData = runningFindUsages.find(key);

View File

@@ -79,6 +79,9 @@ public:
void enableTesting(); void enableTesting();
bool testingEnabled() const; bool testingEnabled() const;
static QString displayNameFromDocumentSymbol(LanguageServerProtocol::SymbolKind kind,
const QString &name, const QString &detail);
signals: signals:
void indexingFinished(); void indexingFinished();
void foundReferences(const QList<Core::SearchResultItem> &items); void foundReferences(const QList<Core::SearchResultItem> &items);

View File

@@ -23,15 +23,17 @@
** **
****************************************************************************/ ****************************************************************************/
#include "clanggloballocatorfilters.h" #include "clangdlocatorfilters.h"
#include "clangdclient.h" #include "clangdclient.h"
#include "clangmodelmanagersupport.h" #include "clangmodelmanagersupport.h"
#include "clangcurrentdocumentfilter.h"
#include <cppeditor/cppeditorconstants.h> #include <cppeditor/cppeditorconstants.h>
#include <cppeditor/cpplocatorfilter.h> #include <cppeditor/cpplocatorfilter.h>
#include <cppeditor/cppmodelmanager.h> #include <cppeditor/cppmodelmanager.h>
#include <cppeditor/indexitem.h> #include <cppeditor/indexitem.h>
#include <languageclient/languageclientutils.h>
#include <languageclient/locatorfilter.h> #include <languageclient/locatorfilter.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <utils/link.h> #include <utils/link.h>
@@ -39,6 +41,8 @@
#include <set> #include <set>
#include <tuple> #include <tuple>
using namespace LanguageServerProtocol;
namespace ClangCodeModel { namespace ClangCodeModel {
namespace Internal { namespace Internal {
@@ -222,5 +226,104 @@ ClangFunctionsFilter::ClangFunctionsFilter()
setDefaultIncludedByDefault(false); setDefaultIncludedByDefault(false);
} }
class CppCurrentDocumentFilter : public ClangCurrentDocumentFilter
{
public:
CppCurrentDocumentFilter()
{
setId({});
setDisplayName({});
setDefaultShortcutString({});
setEnabled(false);
setHidden(true);
}
};
class LspCurrentDocumentFilter : public LanguageClient::DocumentLocatorFilter
{
public:
LspCurrentDocumentFilter()
{
setId({});
setDisplayName({});
setDefaultShortcutString({});
setEnabled(false);
setHidden(true);
forceUse();
}
private:
Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info,
const Core::LocatorFilterEntry &parent) override
{
Core::LocatorFilterEntry entry;
entry.filter = this;
entry.displayName = ClangdClient::displayNameFromDocumentSymbol(
static_cast<SymbolKind>(info.kind()), info.name(),
info.detail().value_or(QString()));
const Position &pos = info.range().start();
entry.internalData = QVariant::fromValue(Utils::LineColumn(pos.line(), pos.character()));
entry.extraInfo = parent.extraInfo;
if (!entry.extraInfo.isEmpty())
entry.extraInfo.append("::");
entry.extraInfo.append(parent.displayName);
// TODO: Can we extend clangd to send visibility information?
entry.displayIcon = LanguageClient::symbolIcon(info.kind());
return entry;
}
};
class ClangdCurrentDocumentFilter::Private
{
public:
CppCurrentDocumentFilter cppFilter;
LspCurrentDocumentFilter lspFilter;
Core::ILocatorFilter *activeFilter = nullptr;
};
ClangdCurrentDocumentFilter::ClangdCurrentDocumentFilter() : d(new Private)
{
setId(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_ID);
setDisplayName(CppEditor::Constants::CURRENT_DOCUMENT_FILTER_DISPLAY_NAME);
setDefaultShortcutString(".");
setPriority(High);
setDefaultIncludedByDefault(false);
setEnabled(false);
connect(Core::EditorManager::instance(), &Core::EditorManager::currentEditorChanged,
this, [this](const Core::IEditor *editor) { setEnabled(editor); });
}
ClangdCurrentDocumentFilter::~ClangdCurrentDocumentFilter() { delete d; }
void ClangdCurrentDocumentFilter::prepareSearch(const QString &entry)
{
const auto doc = TextEditor::TextDocument::currentTextDocument();
QTC_ASSERT(doc, return);
if (const ClangdClient * const client = ClangModelManagerSupport::instance()
->clientForFile(doc->filePath()); client && client->reachable()) {
d->activeFilter = &d->lspFilter;
} else {
d->activeFilter = &d->cppFilter;
}
d->activeFilter->prepareSearch(entry);
}
QList<Core::LocatorFilterEntry> ClangdCurrentDocumentFilter::matchesFor(
QFutureInterface<Core::LocatorFilterEntry> &future, const QString &entry)
{
QTC_ASSERT(d->activeFilter, return {});
return d->activeFilter->matchesFor(future, entry);
}
void ClangdCurrentDocumentFilter::accept(Core::LocatorFilterEntry selection, QString *newText,
int *selectionStart, int *selectionLength) const
{
QTC_ASSERT(d->activeFilter, return);
d->activeFilter->accept(selection, newText, selectionStart, selectionLength);
}
} // namespace Internal } // namespace Internal
} // namespace ClangCodeModel } // namespace ClangCodeModel

View File

@@ -60,5 +60,22 @@ public:
ClangFunctionsFilter(); ClangFunctionsFilter();
}; };
class ClangdCurrentDocumentFilter : public Core::ILocatorFilter
{
public:
ClangdCurrentDocumentFilter();
~ClangdCurrentDocumentFilter() override;
private:
void prepareSearch(const QString &entry) override;
QList<Core::LocatorFilterEntry> matchesFor(QFutureInterface<Core::LocatorFilterEntry> &future,
const QString &entry) override;
void accept(Core::LocatorFilterEntry selection, QString *newText,
int *selectionStart, int *selectionLength) const override;
class Private;
Private * const d;
};
} // namespace Internal } // namespace Internal
} // namespace ClangCodeModel } // namespace ClangCodeModel

View File

@@ -26,12 +26,11 @@
#include "clangmodelmanagersupport.h" #include "clangmodelmanagersupport.h"
#include "clangconstants.h" #include "clangconstants.h"
#include "clangcurrentdocumentfilter.h"
#include "clangdclient.h" #include "clangdclient.h"
#include "clangdquickfixfactory.h" #include "clangdquickfixfactory.h"
#include "clangeditordocumentprocessor.h" #include "clangeditordocumentprocessor.h"
#include "clangfollowsymbol.h" #include "clangfollowsymbol.h"
#include "clanggloballocatorfilters.h" #include "clangdlocatorfilters.h"
#include "clanghoverhandler.h" #include "clanghoverhandler.h"
#include "clangoverviewmodel.h" #include "clangoverviewmodel.h"
#include "clangprojectsettings.h" #include "clangprojectsettings.h"
@@ -113,8 +112,7 @@ ClangModelManagerSupport::ClangModelManagerSupport()
m_instance = this; m_instance = this;
watchForExternalChanges(); watchForExternalChanges();
CppEditor::CppModelManager::instance()->setCurrentDocumentFilter( cppModelManager()->setCurrentDocumentFilter(std::make_unique<ClangdCurrentDocumentFilter>());
std::make_unique<ClangCurrentDocumentFilter>());
cppModelManager()->setLocatorFilter(std::make_unique<ClangGlobalSymbolFilter>()); cppModelManager()->setLocatorFilter(std::make_unique<ClangGlobalSymbolFilter>());
cppModelManager()->setClassesFilter(std::make_unique<ClangClassesFilter>()); cppModelManager()->setClassesFilter(std::make_unique<ClangClassesFilter>());
cppModelManager()->setFunctionsFilter(std::make_unique<ClangFunctionsFilter>()); cppModelManager()->setFunctionsFilter(std::make_unique<ClangFunctionsFilter>());

View File

@@ -393,7 +393,8 @@ void ClangdTestFollowSymbol::test()
timer.stop(); timer.stop();
QCOMPARE(actualLink.targetFilePath, filePath(targetFile)); QCOMPARE(actualLink.targetFilePath, filePath(targetFile));
QEXPECT_FAIL("union member ref", "https://github.com/clangd/clangd/issues/877", Abort); if (client()->versionNumber() < QVersionNumber(14))
QEXPECT_FAIL("union member ref", "https://github.com/clangd/clangd/issues/877", Abort);
QCOMPARE(actualLink.targetLine, targetLine); QCOMPARE(actualLink.targetLine, targetLine);
QCOMPARE(actualLink.targetColumn + 1, targetColumn); QCOMPARE(actualLink.targetColumn + 1, targetColumn);
} }

View File

@@ -340,9 +340,12 @@ static FileInfos sortedFileInfos(const QVector<CppEditor::ProjectPart::ConstPtr>
if (file.path == CppEditor::CppModelManager::configurationFileName()) if (file.path == CppEditor::CppModelManager::configurationFileName())
continue; continue;
if (file.active && CppEditor::ProjectFile::isSource(file.kind)) { if (file.active
&& (CppEditor::ProjectFile::isSource(file.kind)
|| CppEditor::ProjectFile::isHeader(file.kind))) {
ProjectFile::Kind sourceKind = CppEditor::ProjectFile::sourceKind(file.kind);
fileInfos.emplace_back(Utils::FilePath::fromString(file.path), fileInfos.emplace_back(Utils::FilePath::fromString(file.path),
file.kind, sourceKind,
projectPart); projectPart);
} }
} }

View File

@@ -160,11 +160,12 @@ static FileInfo getFileInfo(const FilePath &file, Project *project)
if (!projectFile.active) if (!projectFile.active)
continue; continue;
// found the best candidate, early return // found the best candidate, early return
ProjectFile::Kind sourceKind = ProjectFile::sourceKind(projectFile.kind);
if (projectPart->buildTargetType != BuildTargetType::Unknown) if (projectPart->buildTargetType != BuildTargetType::Unknown)
return FileInfo(projectFilePath, projectFile.kind, projectPart); return FileInfo(projectFilePath, sourceKind, projectPart);
// found something but keep looking for better candidates // found something but keep looking for better candidates
if (candidate.projectPart.isNull()) if (candidate.projectPart.isNull())
candidate = FileInfo(projectFilePath, projectFile.kind, projectPart); candidate = FileInfo(projectFilePath, sourceKind, projectPart);
} }
} }

View File

@@ -213,7 +213,7 @@ void CMakeToolSettingsAccessor::saveCMakeTools(const QList<CMakeTool *> &cmakeTo
for (const CMakeTool *item : cmakeTools) { for (const CMakeTool *item : cmakeTools) {
Utils::FilePath fi = item->cmakeExecutable(); Utils::FilePath fi = item->cmakeExecutable();
if (fi.isExecutableFile()) { if (fi.needsDevice() || fi.isExecutableFile()) { // be graceful for device related stuff
QVariantMap tmp = item->toMap(); QVariantMap tmp = item->toMap();
if (tmp.isEmpty()) if (tmp.isEmpty())
continue; continue;

View File

@@ -87,6 +87,37 @@ bool ProjectFile::isAmbiguousHeader(const QString &filePath)
return filePath.endsWith(".h"); return filePath.endsWith(".h");
} }
ProjectFile::Kind ProjectFile::sourceForHeaderKind(ProjectFile::Kind kind)
{
ProjectFile::Kind sourceKind;
switch (kind) {
case ProjectFile::CHeader:
sourceKind = ProjectFile::CSource;
break;
case ProjectFile::ObjCHeader:
sourceKind = ProjectFile::ObjCSource;
break;
case ProjectFile::ObjCXXHeader:
sourceKind = ProjectFile::ObjCXXSource;
break;
case ProjectFile::Unsupported: // no file extension, e.g. stl headers
case ProjectFile::AmbiguousHeader:
case ProjectFile::CXXHeader:
default:
sourceKind = ProjectFile::CXXSource;
}
return sourceKind;
}
ProjectFile::Kind ProjectFile::sourceKind(Kind kind)
{
ProjectFile::Kind sourceKind = kind;
if (ProjectFile::isHeader(kind))
sourceKind = ProjectFile::sourceForHeaderKind(kind);
return sourceKind;
}
bool ProjectFile::isHeader(ProjectFile::Kind kind) bool ProjectFile::isHeader(ProjectFile::Kind kind)
{ {
switch (kind) { switch (kind) {

View File

@@ -53,6 +53,9 @@ public:
static Kind classifyByMimeType(const QString &mt); static Kind classifyByMimeType(const QString &mt);
static Kind classify(const QString &filePath); static Kind classify(const QString &filePath);
static Kind sourceForHeaderKind(Kind kind);
static Kind sourceKind(Kind kind);
static bool isSource(Kind kind); static bool isSource(Kind kind);
static bool isHeader(Kind kind); static bool isHeader(Kind kind);
static bool isC(Kind kind); static bool isC(Kind kind);

View File

@@ -61,6 +61,6 @@ updateCodeActionRefactoringMarker(Client *client,
const LanguageServerProtocol::CodeAction &action, const LanguageServerProtocol::CodeAction &action,
const LanguageServerProtocol::DocumentUri &uri); const LanguageServerProtocol::DocumentUri &uri);
void updateEditorToolBar(Core::IEditor *editor); void updateEditorToolBar(Core::IEditor *editor);
const QIcon symbolIcon(int type); const QIcon LANGUAGECLIENT_EXPORT symbolIcon(int type);
} // namespace LanguageClient } // namespace LanguageClient

View File

@@ -63,8 +63,8 @@ void DocumentLocatorFilter::updateCurrentClient()
TextEditor::TextDocument *document = TextEditor::TextDocument::currentTextDocument(); TextEditor::TextDocument *document = TextEditor::TextDocument::currentTextDocument();
if (Client *client = LanguageClientManager::clientForDocument(document); if (Client *client = LanguageClientManager::clientForDocument(document);
client && client->locatorsEnabled()) { client && (client->locatorsEnabled() || m_forced)) {
setEnabled(true); setEnabled(!m_forced);
if (m_symbolCache != client->documentSymbolCache()) { if (m_symbolCache != client->documentSymbolCache()) {
disconnect(m_updateSymbolsConnection); disconnect(m_updateSymbolsConnection);
m_symbolCache = client->documentSymbolCache(); m_symbolCache = client->documentSymbolCache();
@@ -98,8 +98,8 @@ void DocumentLocatorFilter::resetSymbols()
m_currentSymbols.reset(); m_currentSymbols.reset();
} }
Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info, static Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info,
Core::ILocatorFilter *filter) Core::ILocatorFilter *filter)
{ {
Core::LocatorFilterEntry entry; Core::LocatorFilterEntry entry;
entry.filter = filter; entry.filter = filter;
@@ -109,13 +109,31 @@ Core::LocatorFilterEntry generateLocatorEntry(const SymbolInformation &info,
entry.displayIcon = symbolIcon(info.kind()); entry.displayIcon = symbolIcon(info.kind());
entry.internalData = QVariant::fromValue(info.location().toLink()); entry.internalData = QVariant::fromValue(info.location().toLink());
return entry; return entry;
} }
Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info, Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(const SymbolInformation &info)
Core::ILocatorFilter *filter)
{ {
return LanguageClient::generateLocatorEntry(info, this);
}
QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateLocatorEntries(
const SymbolInformation &info, const QRegularExpression &regexp,
const Core::LocatorFilterEntry &parent)
{
Q_UNUSED(parent)
if (regexp.match(info.name()).hasMatch())
return {generateLocatorEntry(info)};
return {};
}
Core::LocatorFilterEntry DocumentLocatorFilter::generateLocatorEntry(
const DocumentSymbol &info,
const Core::LocatorFilterEntry &parent)
{
Q_UNUSED(parent)
Core::LocatorFilterEntry entry; Core::LocatorFilterEntry entry;
entry.filter = filter; entry.filter = this;
entry.displayName = info.name(); entry.displayName = info.name();
if (Utils::optional<QString> detail = info.detail()) if (Utils::optional<QString> detail = info.detail())
entry.extraInfo = detail.value_or(QString()); entry.extraInfo = detail.value_or(QString());
@@ -125,6 +143,23 @@ Core::LocatorFilterEntry generateLocatorEntry(const DocumentSymbol &info,
return entry; return entry;
} }
QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateLocatorEntries(
const DocumentSymbol &info, const QRegularExpression &regexp,
const Core::LocatorFilterEntry &parent)
{
QList<Core::LocatorFilterEntry> entries;
const QList<DocumentSymbol> children = info.children().value_or(QList<DocumentSymbol>());
const bool hasMatch = regexp.match(info.name()).hasMatch();
Core::LocatorFilterEntry entry;
if (hasMatch || !children.isEmpty())
entry = generateLocatorEntry(info, parent);
if (hasMatch)
entries << entry;
for (const DocumentSymbol &child : children)
entries << generateLocatorEntries(child, regexp, entry);
return entries;
}
template<class T> template<class T>
QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateEntries(const QList<T> &list, QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateEntries(const QList<T> &list,
const QString &filter) const QString &filter)
@@ -138,11 +173,8 @@ QList<Core::LocatorFilterEntry> DocumentLocatorFilter::generateEntries(const QLi
if (!regexp.isValid()) if (!regexp.isValid())
return entries; return entries;
for (const T &item : list) { for (const T &item : list)
QRegularExpressionMatch match = regexp.match(item.name()); entries << generateLocatorEntries(item, regexp, {});
if (match.hasMatch())
entries << generateLocatorEntry(item, this);
}
return entries; return entries;
} }

View File

@@ -26,6 +26,7 @@
#pragma once #pragma once
#include "client.h" #include "client.h"
#include "languageclient_global.h"
#include <coreplugin/locator/ilocatorfilter.h> #include <coreplugin/locator/ilocatorfilter.h>
#include <languageserverprotocol/lsptypes.h> #include <languageserverprotocol/lsptypes.h>
@@ -38,7 +39,7 @@ namespace Core { class IEditor; }
namespace LanguageClient { namespace LanguageClient {
class DocumentLocatorFilter : public Core::ILocatorFilter class LANGUAGECLIENT_EXPORT DocumentLocatorFilter : public Core::ILocatorFilter
{ {
Q_OBJECT Q_OBJECT
public: public:
@@ -57,6 +58,8 @@ signals:
void symbolsUpToDate(QPrivateSignal); void symbolsUpToDate(QPrivateSignal);
protected: protected:
void forceUse() { m_forced = true; }
QPointer<DocumentSymbolCache> m_symbolCache; QPointer<DocumentSymbolCache> m_symbolCache;
LanguageServerProtocol::DocumentUri m_currentUri; LanguageServerProtocol::DocumentUri m_currentUri;
@@ -67,11 +70,25 @@ private:
template<class T> template<class T>
QList<Core::LocatorFilterEntry> generateEntries(const QList<T> &list, const QString &filter); QList<Core::LocatorFilterEntry> generateEntries(const QList<T> &list, const QString &filter);
QList<Core::LocatorFilterEntry> generateLocatorEntries(
const LanguageServerProtocol::SymbolInformation &info,
const QRegularExpression &regexp,
const Core::LocatorFilterEntry &parent);
QList<Core::LocatorFilterEntry> generateLocatorEntries(
const LanguageServerProtocol::DocumentSymbol &info,
const QRegularExpression &regexp,
const Core::LocatorFilterEntry &parent);
virtual Core::LocatorFilterEntry generateLocatorEntry(
const LanguageServerProtocol::DocumentSymbol &info,
const Core::LocatorFilterEntry &parent);
virtual Core::LocatorFilterEntry generateLocatorEntry(
const LanguageServerProtocol::SymbolInformation &info);
QMutex m_mutex; QMutex m_mutex;
QMetaObject::Connection m_updateSymbolsConnection; QMetaObject::Connection m_updateSymbolsConnection;
QMetaObject::Connection m_resetSymbolsConnection; QMetaObject::Connection m_resetSymbolsConnection;
Utils::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols; Utils::optional<LanguageServerProtocol::DocumentSymbolsResult> m_currentSymbols;
bool m_forced = false;
}; };
class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter

View File

@@ -3313,7 +3313,7 @@ void ProjectExplorerPluginPrivate::openRecentProject(const QString &fileName)
{ {
if (!fileName.isEmpty()) { if (!fileName.isEmpty()) {
ProjectExplorerPlugin::OpenProjectResult result ProjectExplorerPlugin::OpenProjectResult result
= ProjectExplorerPlugin::openProject(FilePath::fromString(fileName)); = ProjectExplorerPlugin::openProject(FilePath::fromUserInput(fileName));
if (!result) if (!result)
ProjectExplorerPlugin::showOpenProjectError(result); ProjectExplorerPlugin::showOpenProjectError(result);
} }

View File

@@ -448,7 +448,7 @@ void RewriterView::auxiliaryDataChanged(const ModelNode &node, const PropertyNam
return; return;
if (node.isRootNode()) { if (node.isRootNode()) {
if (name == "width" || name == "height" || name == "autoSize") if (name == "width" || name == "height" || name == "autoSize" || name == "formeditorColor")
return; return;
} }

View File

@@ -49,9 +49,9 @@ ProFileCache::ProFileCache()
ProFileCache::~ProFileCache() ProFileCache::~ProFileCache()
{ {
foreach (const Entry &ent, parsed_files) for (const auto &keyValuePair : parsed_files)
if (ent.pro) if (keyValuePair.second.pro)
ent.pro->deref(); keyValuePair.second.pro->deref();
QMakeVfs::deref(); QMakeVfs::deref();
} }
@@ -72,20 +72,37 @@ void ProFileCache::discardFile(int id)
#endif #endif
auto it = parsed_files.find(id); auto it = parsed_files.find(id);
if (it != parsed_files.end()) { if (it != parsed_files.end()) {
Entry &entry = it->second;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
if (it->locker) { Entry::Locker *locker = entry.locker;
if (!it->locker->done) { if (locker) { // Either it's still being prepared or it's already done but someone
++it->locker->waiters; // else started waiting for it when it wasn't ready yet
it->locker->cond.wait(&mutex); // and is still waiting.
if (!--it->locker->waiters) { if (!locker->done) {
delete it->locker; ++locker->waiters;
it->locker = 0; locker->cond.wait(&mutex); // Mutex is unlocked and relocked,
// everything may happen in this time window
it = parsed_files.find(id); // In meantime the iterator could have
// been invalidated, search for it again
Q_ASSERT(it != parsed_files.end()); // This would mean that some other
// waiter removed our entry, but only
// the last waiter should do it
if (!--locker->waiters) {
delete locker;
} else {
// There are still other waiters. Do nothing now.
locker->removeOnLastWaiter = true;
return;
} }
} else if (locker->waiters) {
// It's done but some waiters are still awaiting to be woken.
locker->removeOnLastWaiter = true; // Mark it for other waiters
return;
} }
} }
#endif #endif
if (it->pro) if (entry.pro)
it->pro->deref(); entry.pro->deref();
parsed_files.erase(it); parsed_files.erase(it);
} }
} }
@@ -95,26 +112,53 @@ void ProFileCache::discardFiles(const QString &prefix, QMakeVfs *vfs)
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
QMutexLocker lck(&mutex); QMutexLocker lck(&mutex);
#endif #endif
auto it = parsed_files.begin(), end = parsed_files.end(); auto it = parsed_files.begin();
while (it != end) { while (it != parsed_files.end()) {
const int id = it->first;
// Note: this is empty for virtual files from other VFSes. // Note: this is empty for virtual files from other VFSes.
QString fn = vfs->fileNameForId(it.key()); const QString fn = vfs->fileNameForId(id);
if (fn.startsWith(prefix)) { if (fn.startsWith(prefix)) {
bool continueFromScratch = false;
Entry &entry = it->second;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
if (it->locker) { Entry::Locker *locker = entry.locker;
if (!it->locker->done) { if (locker) { // Either it's still being prepared or it's already done but someone
++it->locker->waiters; // else started waiting for it when it wasn't ready yet
it->locker->cond.wait(&mutex); // and is still waiting.
if (!--it->locker->waiters) { if (!locker->done) { // It's still being prepared.
delete it->locker; ++locker->waiters;
it->locker = 0; locker->cond.wait(&mutex); // Mutex is unlocked and relocked,
// everything may happen in this time window
it = parsed_files.find(id); // In meantime the iterator could have
// been invalidated, search for it again
Q_ASSERT(it != parsed_files.end()); // This would mean that some other
// waiter removed our entry, but only
// the last waiter should do it
if (!--locker->waiters) {
delete locker; // No more waiters, remove locker and entry
continueFromScratch = true;
} else {
// There are still other waiters. Do nothing now
locker->removeOnLastWaiter = true;
it = parsed_files.begin(); // Start from scratch, as new matching
// entries could have appeared.
// If we hit it again, we will skip it
// as the locker is already marked as done
continue;
} }
} else if (locker->waiters) {
// It's done but some waiters are still awaiting to be woken.
locker->removeOnLastWaiter = true; // Mark it for other waiters
++it; // We skip it for now, other waiter will do the job
continue;
} }
} }
#endif #endif
if (it->pro) if (entry.pro)
it->pro->deref(); entry.pro->deref();
it = parsed_files.erase(it); it = parsed_files.erase(it);
if (continueFromScratch)
it = parsed_files.begin();
} else { } else {
++it; ++it;
} }
@@ -187,20 +231,44 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
if ((flags & ParseUseCache) && m_cache) { if ((flags & ParseUseCache) && m_cache) {
ProFileCache::Entry *ent; ProFileCache::Entry *ent;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
QMutexLocker locker(&m_cache->mutex); QMutexLocker lck(&m_cache->mutex);
#endif #endif
auto it = m_cache->parsed_files.find(id); auto it = m_cache->parsed_files.find(id);
if (it != m_cache->parsed_files.end()) { if (it != m_cache->parsed_files.end()) {
ent = &*it; ent = &it->second;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
if (ent->locker && !ent->locker->done) { ProFileCache::Entry::Locker *locker = ent->locker;
++ent->locker->waiters; if (locker) { // Either it's still being prepared or it's already done but someone
QThreadPool::globalInstance()->releaseThread(); // else started waiting for it when it wasn't ready yet
ent->locker->cond.wait(locker.mutex()); // and is still waiting.
QThreadPool::globalInstance()->reserveThread(); if (!locker->done) { // It's still being prepared.
if (!--ent->locker->waiters) { ++locker->waiters;
delete ent->locker; QThreadPool::globalInstance()->releaseThread();
ent->locker = 0; locker->cond.wait(lck.mutex()); // Mutex is unlocked and relocked,
// everything may happen in this time window
QThreadPool::globalInstance()->reserveThread();
it = m_cache->parsed_files.find(id); // In meantime the iterator could have
// been invalidated, search for it again
Q_ASSERT(it != m_cache->parsed_files.end()); // This would mean that some other
// waiter removed our entry, but only
// the last waiter should do it
const bool remove = locker->removeOnLastWaiter; // Some waiter marked this
// entry for removal.
if (!--locker->waiters) { // If we were the last waiter
delete locker; // we do it now
ent->locker = 0;
if (remove) {
if (ent->pro)
ent->pro->deref();
m_cache->parsed_files.erase(it);
return nullptr;
}
}
if (remove)
return nullptr;
} else if (locker->removeOnLastWaiter) {
return nullptr;
} }
} }
#endif #endif
@@ -210,7 +278,7 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
ent = &m_cache->parsed_files[id]; ent = &m_cache->parsed_files[id];
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
ent->locker = new ProFileCache::Entry::Locker; ent->locker = new ProFileCache::Entry::Locker;
locker.unlock(); lck.unlock(); // We unlock the mutex and open a time window
#endif #endif
QString contents; QString contents;
if (readFile(id, flags, &contents)) { if (readFile(id, flags, &contents)) {
@@ -222,11 +290,17 @@ ProFile *QMakeParser::parsedProFile(const QString &fileName, ParseFlags flags)
} }
ent->pro = pro; ent->pro = pro;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
locker.relock(); lck.relock(); // We relock it back and close the window. Someone could have added a new
if (ent->locker->waiters) { // entry to the parsed_files list (or removed one). However, no one
ent->locker->done = true; // was awoken for our id in this time window.
it = m_cache->parsed_files.find(id); // In meantime the iterator could have
// been invalidated, search for it again
Q_ASSERT(it != m_cache->parsed_files.end()); // This would mean that our reference
// is also invalid
if (ent->locker->waiters) { // Someone runs getter or wants to remove it
ent->locker->done = true; // The structure is ready
ent->locker->cond.wakeAll(); ent->locker->cond.wakeAll();
} else { } else { // No one was interested, remove locker as everything is ready now
delete ent->locker; delete ent->locker;
ent->locker = 0; ent->locker = 0;
} }

View File

@@ -29,13 +29,14 @@
#include "qmakevfs.h" #include "qmakevfs.h"
#include "proitems.h" #include "proitems.h"
#include <qhash.h>
#include <qstack.h> #include <qstack.h>
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
# include <qmutex.h> # include <qmutex.h>
# include <qwaitcondition.h> # include <qwaitcondition.h>
#endif #endif
#include <unordered_map>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QMAKE_EXPORT QMakeParserHandler class QMAKE_EXPORT QMakeParserHandler
{ {
@@ -208,16 +209,16 @@ private:
ProFile *pro; ProFile *pro;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
struct Locker { struct Locker {
Locker() : waiters(0), done(false) {}
QWaitCondition cond; QWaitCondition cond;
int waiters; int waiters = 0;
bool done; bool done = false;
bool removeOnLastWaiter = false;
}; };
Locker *locker; Locker *locker;
#endif #endif
}; };
QHash<int, Entry> parsed_files; std::unordered_map<int, Entry> parsed_files;
#ifdef PROPARSER_THREAD_SAFE #ifdef PROPARSER_THREAD_SAFE
QMutex mutex; QMutex mutex;
#endif #endif