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:
Christian Kandeler
2023-05-17 13:45:56 +02:00
parent 5abb1959c5
commit aa5ddaf412
4 changed files with 66 additions and 4 deletions

View File

@@ -352,10 +352,24 @@ 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)) {
client->switchHeaderSource(filePath, inNextSplit); switch (ClangdProjectSettings(client->project()).settings().headerSourceSwitchMode) {
else case ClangdSettings::HeaderSourceSwitchMode::BuiltinOnly:
CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin); CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin);
return;
case ClangdSettings::HeaderSourceSwitchMode::ClangdOnly:
client->switchHeaderSource(filePath, inNextSplit);
return;
case ClangdSettings::HeaderSourceSwitchMode::Both:
const FilePath otherFile = correspondingHeaderOrSource(filePath);
if (!otherFile.isEmpty())
openEditor(otherFile, inNextSplit);
else
client->switchHeaderSource(filePath, inNextSplit);
return;
}
}
CppModelManager::switchHeaderSource(inNextSplit, CppModelManager::Backend::Builtin);
} }
void ClangModelManagerSupport::checkUnused(const Link &link, SearchResult *search, void ClangModelManagerSupport::checkUnused(const Link &link, SearchResult *search,

View File

@@ -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();

View File

@@ -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; }

View File

@@ -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();