forked from qt-creator/qt-creator
ClangCodeModel: Switch to LSP-based UI header approach
Generating ui headers in a well-known path and then including that one in the compilation database does not work in the presence of multiple ui files with the same name. As it turns out, we don't have to generate any files at all; instead, we pass the file contents directly to clangd, which then uses them when parsing includes of the respective header. User-visible behavior change apart from the abovementioned bug fix: Tooltips and "follow symbol" on the include directive now always use the actual location of the header provided by the build system. Fixes: QTCREATORBUG-27584 Change-Id: I6b13e12cb3a365199567b0bc824d12b373117697 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -100,6 +100,30 @@ static const QList<TextEditor::TextDocument *> allCppDocuments()
|
||||
return Utils::qobject_container_cast<TextEditor::TextDocument *>(documents);
|
||||
}
|
||||
|
||||
static bool fileIsProjectBuildArtifact(const Client *client, const Utils::FilePath &filePath)
|
||||
{
|
||||
if (const auto p = client->project()) {
|
||||
if (const auto t = p->activeTarget()) {
|
||||
if (const auto bc = t->activeBuildConfiguration()) {
|
||||
if (filePath.isChildOf(bc->buildDirectory()))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Client *clientForGeneratedFile(const Utils::FilePath &filePath)
|
||||
{
|
||||
for (Client * const client : LanguageClientManager::clients()) {
|
||||
if (qobject_cast<ClangdClient *>(client) && client->reachable()
|
||||
&& fileIsProjectBuildArtifact(client, filePath)) {
|
||||
return client;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ClangModelManagerSupport::ClangModelManagerSupport()
|
||||
{
|
||||
QTC_CHECK(!m_instance);
|
||||
@@ -344,7 +368,7 @@ void ClangModelManagerSupport::updateLanguageClient(
|
||||
if (Client * const oldClient = clientForProject(project))
|
||||
LanguageClientManager::shutdownClient(oldClient);
|
||||
ClangdClient * const client = createClient(project, jsonDbDir);
|
||||
connect(client, &Client::initialized, this, [client, project, projectInfo, jsonDbDir] {
|
||||
connect(client, &Client::initialized, this, [this, client, project, projectInfo, jsonDbDir] {
|
||||
using namespace ProjectExplorer;
|
||||
if (!SessionManager::hasProject(project))
|
||||
return;
|
||||
@@ -384,6 +408,23 @@ void ClangModelManagerSupport::updateLanguageClient(
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = m_queuedShadowDocuments.begin(); it != m_queuedShadowDocuments.end();) {
|
||||
if (fileIsProjectBuildArtifact(client, it.key())) {
|
||||
if (it.value().isEmpty())
|
||||
client->removeShadowDocument(it.key());
|
||||
else
|
||||
client->setShadowDocument(it.key(), it.value());
|
||||
ClangdClient::handleUiHeaderChange(it.key().fileName());
|
||||
it = m_queuedShadowDocuments.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
connect(client, &Client::shadowDocumentSwitched, this,
|
||||
[](const Utils::FilePath &fp) {
|
||||
ClangdClient::handleUiHeaderChange(fp.fileName());
|
||||
});
|
||||
|
||||
if (client->state() == Client::Initialized)
|
||||
updateParserConfig();
|
||||
else
|
||||
@@ -593,18 +634,28 @@ void ClangModelManagerSupport::onAbstractEditorSupportContentsUpdated(const QStr
|
||||
|
||||
if (content.size() == 0)
|
||||
return; // Generation not yet finished.
|
||||
|
||||
m_uiHeaderOnDiskManager.write(filePath, content);
|
||||
ClangdClient::handleUiHeaderChange(Utils::FilePath::fromString(filePath).fileName());
|
||||
const auto fp = Utils::FilePath::fromString(filePath);
|
||||
const QString stringContent = QString::fromUtf8(content);
|
||||
if (Client * const client = clientForGeneratedFile(fp)) {
|
||||
client->setShadowDocument(fp, stringContent);
|
||||
ClangdClient::handleUiHeaderChange(fp.fileName());
|
||||
QTC_CHECK(m_queuedShadowDocuments.remove(fp) == 0);
|
||||
} else {
|
||||
m_queuedShadowDocuments.insert(fp, stringContent);
|
||||
}
|
||||
}
|
||||
|
||||
void ClangModelManagerSupport::onAbstractEditorSupportRemoved(const QString &filePath)
|
||||
{
|
||||
QTC_ASSERT(!filePath.isEmpty(), return);
|
||||
|
||||
if (!cppModelManager()->cppEditorDocument(filePath)) {
|
||||
m_uiHeaderOnDiskManager.remove(filePath);
|
||||
ClangdClient::handleUiHeaderChange(Utils::FilePath::fromString(filePath).fileName());
|
||||
const auto fp = Utils::FilePath::fromString(filePath);
|
||||
if (Client * const client = clientForGeneratedFile(fp)) {
|
||||
client->removeShadowDocument(fp);
|
||||
ClangdClient::handleUiHeaderChange(fp.fileName());
|
||||
QTC_CHECK(m_queuedShadowDocuments.remove(fp) == 0);
|
||||
} else {
|
||||
m_queuedShadowDocuments.insert(fp, {});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -738,16 +789,6 @@ ClangModelManagerSupport *ClangModelManagerSupport::instance()
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
QString ClangModelManagerSupport::dummyUiHeaderOnDiskPath(const QString &filePath) const
|
||||
{
|
||||
return m_uiHeaderOnDiskManager.mapPath(filePath);
|
||||
}
|
||||
|
||||
QString ClangModelManagerSupport::dummyUiHeaderOnDiskDirPath() const
|
||||
{
|
||||
return m_uiHeaderOnDiskManager.directoryPath();
|
||||
}
|
||||
|
||||
QString ClangModelManagerSupportProvider::id() const
|
||||
{
|
||||
return QLatin1String(Constants::CLANG_MODELMANAGERSUPPORT_ID);
|
||||
|
||||
Reference in New Issue
Block a user