forked from qt-creator/qt-creator
ClangCodeModel: Let user decide how to do the header/source switch
While clangd's AST matching can find source files at any location, it also has a number of annoying bugs that break the functionality for some users. This patch brings back the previous "try built-in first" logic, but also lets users choose their preferred backend. Task-number: QTCREATORBUG-29175 Change-Id: I6b854ed05652e6468509e5748a83a8f9bf76fc20 Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
@@ -352,9 +352,23 @@ void ClangModelManagerSupport::findUsages(const CursorInEditor &cursor) const
|
|||||||
|
|
||||||
void ClangModelManagerSupport::switchHeaderSource(const FilePath &filePath, bool inNextSplit)
|
void ClangModelManagerSupport::switchHeaderSource(const FilePath &filePath, bool inNextSplit)
|
||||||
{
|
{
|
||||||
if (ClangdClient * const client = clientForFile(filePath))
|
if (ClangdClient * const client = clientForFile(filePath)) {
|
||||||
|
switch (ClangdProjectSettings(client->project()).settings().headerSourceSwitchMode) {
|
||||||
|
case ClangdSettings::HeaderSourceSwitchMode::BuiltinOnly:
|
||||||
|
CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin);
|
||||||
|
return;
|
||||||
|
case ClangdSettings::HeaderSourceSwitchMode::ClangdOnly:
|
||||||
client->switchHeaderSource(filePath, inNextSplit);
|
client->switchHeaderSource(filePath, inNextSplit);
|
||||||
|
return;
|
||||||
|
case ClangdSettings::HeaderSourceSwitchMode::Both:
|
||||||
|
const FilePath otherFile = correspondingHeaderOrSource(filePath);
|
||||||
|
if (!otherFile.isEmpty())
|
||||||
|
openEditor(otherFile, inNextSplit);
|
||||||
else
|
else
|
||||||
|
client->switchHeaderSource(filePath, inNextSplit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin);
|
CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -64,6 +64,9 @@ static QString useClangdKey() { return QLatin1String("UseClangdV7"); }
|
|||||||
static QString clangdPathKey() { return QLatin1String("ClangdPath"); }
|
static QString clangdPathKey() { return QLatin1String("ClangdPath"); }
|
||||||
static QString clangdIndexingKey() { return QLatin1String("ClangdIndexing"); }
|
static QString clangdIndexingKey() { return QLatin1String("ClangdIndexing"); }
|
||||||
static QString clangdIndexingPriorityKey() { return QLatin1String("ClangdIndexingPriority"); }
|
static QString clangdIndexingPriorityKey() { return QLatin1String("ClangdIndexingPriority"); }
|
||||||
|
static QString clangdHeaderSourceSwitchModeKey() {
|
||||||
|
return QLatin1String("ClangdHeaderSourceSwitchMode");
|
||||||
|
}
|
||||||
static QString clangdHeaderInsertionKey() { return QLatin1String("ClangdHeaderInsertion"); }
|
static QString clangdHeaderInsertionKey() { return QLatin1String("ClangdHeaderInsertion"); }
|
||||||
static QString clangdThreadLimitKey() { return QLatin1String("ClangdThreadLimit"); }
|
static QString clangdThreadLimitKey() { return QLatin1String("ClangdThreadLimit"); }
|
||||||
static QString clangdDocumentThresholdKey() { return QLatin1String("ClangdDocumentThreshold"); }
|
static QString clangdDocumentThresholdKey() { return QLatin1String("ClangdDocumentThreshold"); }
|
||||||
@@ -229,6 +232,16 @@ QString ClangdSettings::priorityToDisplayString(const IndexingPriority &priority
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString ClangdSettings::headerSourceSwitchModeToDisplayString(HeaderSourceSwitchMode mode)
|
||||||
|
{
|
||||||
|
switch (mode) {
|
||||||
|
case HeaderSourceSwitchMode::BuiltinOnly: return Tr::tr("Use Built-in Only");
|
||||||
|
case HeaderSourceSwitchMode::ClangdOnly: return Tr::tr("Use Clangd Only");
|
||||||
|
case HeaderSourceSwitchMode::Both: return Tr::tr("Try Both");
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
ClangdSettings &ClangdSettings::instance()
|
ClangdSettings &ClangdSettings::instance()
|
||||||
{
|
{
|
||||||
static ClangdSettings settings;
|
static ClangdSettings settings;
|
||||||
@@ -528,6 +541,7 @@ QVariantMap ClangdSettings::Data::toMap() const
|
|||||||
: QString());
|
: QString());
|
||||||
map.insert(clangdIndexingKey(), indexingPriority != IndexingPriority::Off);
|
map.insert(clangdIndexingKey(), indexingPriority != IndexingPriority::Off);
|
||||||
map.insert(clangdIndexingPriorityKey(), int(indexingPriority));
|
map.insert(clangdIndexingPriorityKey(), int(indexingPriority));
|
||||||
|
map.insert(clangdHeaderSourceSwitchModeKey(), int(headerSourceSwitchMode));
|
||||||
map.insert(clangdHeaderInsertionKey(), autoIncludeHeaders);
|
map.insert(clangdHeaderInsertionKey(), autoIncludeHeaders);
|
||||||
map.insert(clangdThreadLimitKey(), workerThreadLimit);
|
map.insert(clangdThreadLimitKey(), workerThreadLimit);
|
||||||
map.insert(clangdDocumentThresholdKey(), documentUpdateThreshold);
|
map.insert(clangdDocumentThresholdKey(), documentUpdateThreshold);
|
||||||
@@ -549,6 +563,8 @@ void ClangdSettings::Data::fromMap(const QVariantMap &map)
|
|||||||
const auto it = map.find(clangdIndexingKey());
|
const auto it = map.find(clangdIndexingKey());
|
||||||
if (it != map.end() && !it->toBool())
|
if (it != map.end() && !it->toBool())
|
||||||
indexingPriority = IndexingPriority::Off;
|
indexingPriority = IndexingPriority::Off;
|
||||||
|
headerSourceSwitchMode = HeaderSourceSwitchMode(map.value(clangdHeaderSourceSwitchModeKey(),
|
||||||
|
int(headerSourceSwitchMode)).toInt());
|
||||||
autoIncludeHeaders = map.value(clangdHeaderInsertionKey(), false).toBool();
|
autoIncludeHeaders = map.value(clangdHeaderInsertionKey(), false).toBool();
|
||||||
workerThreadLimit = map.value(clangdThreadLimitKey(), 0).toInt();
|
workerThreadLimit = map.value(clangdThreadLimitKey(), 0).toInt();
|
||||||
documentUpdateThreshold = map.value(clangdDocumentThresholdKey(), 500).toInt();
|
documentUpdateThreshold = map.value(clangdDocumentThresholdKey(), 500).toInt();
|
||||||
|
@@ -84,9 +84,11 @@ class CPPEDITOR_EXPORT ClangdSettings : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
enum class IndexingPriority { Off, Background, Normal, Low, };
|
enum class IndexingPriority { Off, Background, Normal, Low, };
|
||||||
|
enum class HeaderSourceSwitchMode { BuiltinOnly, ClangdOnly, Both };
|
||||||
|
|
||||||
static QString priorityToString(const IndexingPriority &priority);
|
static QString priorityToString(const IndexingPriority &priority);
|
||||||
static QString priorityToDisplayString(const IndexingPriority &priority);
|
static QString priorityToDisplayString(const IndexingPriority &priority);
|
||||||
|
static QString headerSourceSwitchModeToDisplayString(HeaderSourceSwitchMode mode);
|
||||||
|
|
||||||
class CPPEDITOR_EXPORT Data
|
class CPPEDITOR_EXPORT Data
|
||||||
{
|
{
|
||||||
@@ -103,6 +105,7 @@ public:
|
|||||||
&& s1.diagnosticConfigId == s2.diagnosticConfigId
|
&& s1.diagnosticConfigId == s2.diagnosticConfigId
|
||||||
&& s1.workerThreadLimit == s2.workerThreadLimit
|
&& s1.workerThreadLimit == s2.workerThreadLimit
|
||||||
&& s1.indexingPriority == s2.indexingPriority
|
&& s1.indexingPriority == s2.indexingPriority
|
||||||
|
&& s1.headerSourceSwitchMode == s2.headerSourceSwitchMode
|
||||||
&& s1.autoIncludeHeaders == s2.autoIncludeHeaders
|
&& s1.autoIncludeHeaders == s2.autoIncludeHeaders
|
||||||
&& s1.documentUpdateThreshold == s2.documentUpdateThreshold
|
&& s1.documentUpdateThreshold == s2.documentUpdateThreshold
|
||||||
&& s1.sizeThresholdEnabled == s2.sizeThresholdEnabled
|
&& s1.sizeThresholdEnabled == s2.sizeThresholdEnabled
|
||||||
@@ -123,6 +126,7 @@ public:
|
|||||||
qint64 sizeThresholdInKb = 1024;
|
qint64 sizeThresholdInKb = 1024;
|
||||||
bool useClangd = true;
|
bool useClangd = true;
|
||||||
IndexingPriority indexingPriority = IndexingPriority::Low;
|
IndexingPriority indexingPriority = IndexingPriority::Low;
|
||||||
|
HeaderSourceSwitchMode headerSourceSwitchMode = HeaderSourceSwitchMode::Both;
|
||||||
bool autoIncludeHeaders = false;
|
bool autoIncludeHeaders = false;
|
||||||
bool sizeThresholdEnabled = false;
|
bool sizeThresholdEnabled = false;
|
||||||
bool haveCheckedHardwareReqirements = false;
|
bool haveCheckedHardwareReqirements = false;
|
||||||
@@ -143,6 +147,7 @@ public:
|
|||||||
static void setCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs);
|
static void setCustomDiagnosticConfigs(const ClangDiagnosticConfigs &configs);
|
||||||
Utils::FilePath clangdFilePath() const;
|
Utils::FilePath clangdFilePath() const;
|
||||||
IndexingPriority indexingPriority() const { return m_data.indexingPriority; }
|
IndexingPriority indexingPriority() const { return m_data.indexingPriority; }
|
||||||
|
HeaderSourceSwitchMode headerSourceSwitchMode() const { return m_data.headerSourceSwitchMode; }
|
||||||
bool autoIncludeHeaders() const { return m_data.autoIncludeHeaders; }
|
bool autoIncludeHeaders() const { return m_data.autoIncludeHeaders; }
|
||||||
int workerThreadLimit() const { return m_data.workerThreadLimit; }
|
int workerThreadLimit() const { return m_data.workerThreadLimit; }
|
||||||
int documentUpdateThreshold() const { return m_data.documentUpdateThreshold; }
|
int documentUpdateThreshold() const { return m_data.documentUpdateThreshold; }
|
||||||
|
@@ -192,6 +192,7 @@ class ClangdSettingsWidget::Private
|
|||||||
public:
|
public:
|
||||||
QCheckBox useClangdCheckBox;
|
QCheckBox useClangdCheckBox;
|
||||||
QComboBox indexingComboBox;
|
QComboBox indexingComboBox;
|
||||||
|
QComboBox headerSourceSwitchComboBox;
|
||||||
QCheckBox autoIncludeHeadersCheckBox;
|
QCheckBox autoIncludeHeadersCheckBox;
|
||||||
QCheckBox sizeThresholdCheckBox;
|
QCheckBox sizeThresholdCheckBox;
|
||||||
QSpinBox threadLimitSpinBox;
|
QSpinBox threadLimitSpinBox;
|
||||||
@@ -220,6 +221,12 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
|
|||||||
"cores unused.</p>"
|
"cores unused.</p>"
|
||||||
"<p>Normal Priority: Reduced priority compared to interactive work.</p>"
|
"<p>Normal Priority: Reduced priority compared to interactive work.</p>"
|
||||||
"Low Priority: Same priority as other clangd work.");
|
"Low Priority: Same priority as other clangd work.");
|
||||||
|
const QString headerSourceSwitchToolTip = Tr::tr(
|
||||||
|
"<p>Which C/C++ backend to use when switching between header and source file."
|
||||||
|
"<p>The clangd implementation has more capabilities, but also has some bugs not present "
|
||||||
|
"in the built-in variant."
|
||||||
|
"<p>When \"Try Both\" is selected, clangd will be employed only if the built-in variant "
|
||||||
|
"does not find anything.");
|
||||||
const QString workerThreadsToolTip = Tr::tr(
|
const QString workerThreadsToolTip = Tr::tr(
|
||||||
"Number of worker threads used by clangd. Background indexing also uses this many "
|
"Number of worker threads used by clangd. Background indexing also uses this many "
|
||||||
"worker threads.");
|
"worker threads.");
|
||||||
@@ -249,6 +256,15 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
|
|||||||
d->indexingComboBox.setCurrentIndex(d->indexingComboBox.count() - 1);
|
d->indexingComboBox.setCurrentIndex(d->indexingComboBox.count() - 1);
|
||||||
}
|
}
|
||||||
d->indexingComboBox.setToolTip(indexingToolTip);
|
d->indexingComboBox.setToolTip(indexingToolTip);
|
||||||
|
using SwitchMode = ClangdSettings::HeaderSourceSwitchMode;
|
||||||
|
for (SwitchMode mode : {SwitchMode::BuiltinOnly, SwitchMode::ClangdOnly, SwitchMode::Both}) {
|
||||||
|
d->headerSourceSwitchComboBox.addItem(
|
||||||
|
ClangdSettings::headerSourceSwitchModeToDisplayString(mode), int(mode));
|
||||||
|
if (mode == settings.headerSourceSwitchMode())
|
||||||
|
d->headerSourceSwitchComboBox.setCurrentIndex(
|
||||||
|
d->headerSourceSwitchComboBox.count() - 1);
|
||||||
|
}
|
||||||
|
d->headerSourceSwitchComboBox.setToolTip(headerSourceSwitchToolTip);
|
||||||
d->autoIncludeHeadersCheckBox.setText(Tr::tr("Insert header files on completion"));
|
d->autoIncludeHeadersCheckBox.setText(Tr::tr("Insert header files on completion"));
|
||||||
d->autoIncludeHeadersCheckBox.setChecked(settings.autoIncludeHeaders());
|
d->autoIncludeHeadersCheckBox.setChecked(settings.autoIncludeHeaders());
|
||||||
d->autoIncludeHeadersCheckBox.setToolTip(autoIncludeToolTip);
|
d->autoIncludeHeadersCheckBox.setToolTip(autoIncludeToolTip);
|
||||||
@@ -294,6 +310,13 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
|
|||||||
indexingPriorityLabel->setToolTip(indexingToolTip);
|
indexingPriorityLabel->setToolTip(indexingToolTip);
|
||||||
formLayout->addRow(indexingPriorityLabel, indexingPriorityLayout);
|
formLayout->addRow(indexingPriorityLabel, indexingPriorityLayout);
|
||||||
|
|
||||||
|
const auto headerSourceSwitchLayout = new QHBoxLayout;
|
||||||
|
headerSourceSwitchLayout->addWidget(&d->headerSourceSwitchComboBox);
|
||||||
|
headerSourceSwitchLayout->addStretch(1);
|
||||||
|
const auto headerSourceSwitchLabel = new QLabel(Tr::tr("Header/source switch mode:"));
|
||||||
|
headerSourceSwitchLabel->setToolTip(headerSourceSwitchToolTip);
|
||||||
|
formLayout->addRow(headerSourceSwitchLabel, headerSourceSwitchLayout);
|
||||||
|
|
||||||
const auto threadLimitLayout = new QHBoxLayout;
|
const auto threadLimitLayout = new QHBoxLayout;
|
||||||
threadLimitLayout->addWidget(&d->threadLimitSpinBox);
|
threadLimitLayout->addWidget(&d->threadLimitSpinBox);
|
||||||
threadLimitLayout->addStretch(1);
|
threadLimitLayout->addStretch(1);
|
||||||
@@ -449,6 +472,8 @@ ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsD
|
|||||||
this, &ClangdSettingsWidget::settingsDataChanged);
|
this, &ClangdSettingsWidget::settingsDataChanged);
|
||||||
connect(&d->indexingComboBox, &QComboBox::currentIndexChanged,
|
connect(&d->indexingComboBox, &QComboBox::currentIndexChanged,
|
||||||
this, &ClangdSettingsWidget::settingsDataChanged);
|
this, &ClangdSettingsWidget::settingsDataChanged);
|
||||||
|
connect(&d->headerSourceSwitchComboBox, &QComboBox::currentIndexChanged,
|
||||||
|
this, &ClangdSettingsWidget::settingsDataChanged);
|
||||||
connect(&d->autoIncludeHeadersCheckBox, &QCheckBox::toggled,
|
connect(&d->autoIncludeHeadersCheckBox, &QCheckBox::toggled,
|
||||||
this, &ClangdSettingsWidget::settingsDataChanged);
|
this, &ClangdSettingsWidget::settingsDataChanged);
|
||||||
connect(&d->threadLimitSpinBox, &QSpinBox::valueChanged,
|
connect(&d->threadLimitSpinBox, &QSpinBox::valueChanged,
|
||||||
@@ -479,6 +504,8 @@ ClangdSettings::Data ClangdSettingsWidget::settingsData() const
|
|||||||
data.executableFilePath = d->clangdChooser.filePath();
|
data.executableFilePath = d->clangdChooser.filePath();
|
||||||
data.indexingPriority = ClangdSettings::IndexingPriority(
|
data.indexingPriority = ClangdSettings::IndexingPriority(
|
||||||
d->indexingComboBox.currentData().toInt());
|
d->indexingComboBox.currentData().toInt());
|
||||||
|
data.headerSourceSwitchMode = ClangdSettings::HeaderSourceSwitchMode(
|
||||||
|
d->headerSourceSwitchComboBox.currentData().toInt());
|
||||||
data.autoIncludeHeaders = d->autoIncludeHeadersCheckBox.isChecked();
|
data.autoIncludeHeaders = d->autoIncludeHeadersCheckBox.isChecked();
|
||||||
data.workerThreadLimit = d->threadLimitSpinBox.value();
|
data.workerThreadLimit = d->threadLimitSpinBox.value();
|
||||||
data.documentUpdateThreshold = d->documentUpdateThreshold.value();
|
data.documentUpdateThreshold = d->documentUpdateThreshold.value();
|
||||||
|
Reference in New Issue
Block a user