ClangCodeModel: Fix shadow document handling

Our approach was not fully thought through: When we got informed of a
file getting created by an ExtraCompiler, we would make it known to the
first client that came along and then forget about it. This means that
e.g. a source file including a UI header would parse fine with the first
client that opened it, but after switching the build configuration or
possibly even just touching the project file, the UI header would not be
found anymore.
Fix this by keeping the information about generated files around and
attaching them to every newly initialized client.
Note that this state should probably be kept somewhere more central.

Change-Id: Ib1d8cca9258d1962513d8d463f5d16f9ff91a048
Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2023-11-03 09:46:50 +01:00
parent 92ea715c0f
commit a1b78d4234
3 changed files with 14 additions and 18 deletions

View File

@@ -553,17 +553,15 @@ void ClangModelManagerSupport::updateLanguageClient(Project *project)
hasDocuments = true; hasDocuments = true;
} }
for (auto it = m_queuedShadowDocuments.begin(); it != m_queuedShadowDocuments.end();) { for (auto it = m_potentialShadowDocuments.begin();
if (fileIsProjectBuildArtifact(client, it.key())) { it != m_potentialShadowDocuments.end(); ++it) {
if (!fileIsProjectBuildArtifact(client, it.key()))
continue;
if (it.value().isEmpty()) if (it.value().isEmpty())
client->removeShadowDocument(it.key()); client->removeShadowDocument(it.key());
else else
client->setShadowDocument(it.key(), it.value()); client->setShadowDocument(it.key(), it.value());
ClangdClient::handleUiHeaderChange(it.key().fileName()); ClangdClient::handleUiHeaderChange(it.key().fileName());
it = m_queuedShadowDocuments.erase(it);
} else {
++it;
}
} }
updateParserConfig(client); updateParserConfig(client);
@@ -799,10 +797,8 @@ void ClangModelManagerSupport::onAbstractEditorSupportContentsUpdated(const QStr
if (Client * const client = clientForGeneratedFile(fp)) { if (Client * const client = clientForGeneratedFile(fp)) {
client->setShadowDocument(fp, stringContent); client->setShadowDocument(fp, stringContent);
ClangdClient::handleUiHeaderChange(fp.fileName()); ClangdClient::handleUiHeaderChange(fp.fileName());
QTC_CHECK(m_queuedShadowDocuments.remove(fp) == 0);
} else {
m_queuedShadowDocuments.insert(fp, stringContent);
} }
m_potentialShadowDocuments.insert(fp, stringContent);
} }
void ClangModelManagerSupport::onAbstractEditorSupportRemoved(const QString &filePath) void ClangModelManagerSupport::onAbstractEditorSupportRemoved(const QString &filePath)
@@ -813,10 +809,8 @@ void ClangModelManagerSupport::onAbstractEditorSupportRemoved(const QString &fil
if (Client * const client = clientForGeneratedFile(fp)) { if (Client * const client = clientForGeneratedFile(fp)) {
client->removeShadowDocument(fp); client->removeShadowDocument(fp);
ClangdClient::handleUiHeaderChange(fp.fileName()); ClangdClient::handleUiHeaderChange(fp.fileName());
QTC_CHECK(m_queuedShadowDocuments.remove(fp) == 0);
} else {
m_queuedShadowDocuments.insert(fp, {});
} }
m_potentialShadowDocuments.remove(fp);
} }
void addFixItsActionsToMenu(QMenu *menu, const TextEditor::QuickFixOperations &fixItOperations) void addFixItsActionsToMenu(QMenu *menu, const TextEditor::QuickFixOperations &fixItOperations)

View File

@@ -96,7 +96,7 @@ private:
Utils::FutureSynchronizer m_generatorSynchronizer; Utils::FutureSynchronizer m_generatorSynchronizer;
QList<QPointer<ClangdClient>> m_clientsToRestart; QList<QPointer<ClangdClient>> m_clientsToRestart;
QTimer * const m_clientRestartTimer; QTimer * const m_clientRestartTimer;
QHash<Utils::FilePath, QString> m_queuedShadowDocuments; QHash<Utils::FilePath, QString> m_potentialShadowDocuments;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -1058,6 +1058,8 @@ void Client::setShadowDocument(const Utils::FilePath &filePath, const QString &c
if (shadowIt == d->m_shadowDocuments.end()) { if (shadowIt == d->m_shadowDocuments.end()) {
shadowIt = d->m_shadowDocuments.insert(filePath, {content, {}}); shadowIt = d->m_shadowDocuments.insert(filePath, {content, {}});
} else { } else {
if (shadowIt.value().first == content)
return;
shadowIt.value().first = content; shadowIt.value().first = content;
if (!shadowIt.value().second.isEmpty()) { if (!shadowIt.value().second.isEmpty()) {
VersionedTextDocumentIdentifier docId(hostPathToServerUri(filePath)); VersionedTextDocumentIdentifier docId(hostPathToServerUri(filePath));