forked from qt-creator/qt-creator
ClangCodeModel: Check system for clangd suitability on first run
Turn off clangd by default if we think the system does not have enough memory. Inform the user and let them override our decision. Task-number: QTCREATORBUG-19297 Change-Id: Ib9715c2f089c10d7a2a559a25180e9a943c118b1 Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -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
|
||||||
@@ -111,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 {};
|
||||||
|
}
|
||||||
|
@@ -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
|
||||||
@@ -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;
|
||||||
|
@@ -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>());
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user